Spring Boot 아키텍처 : Entity, DTO, Repository, Service, Controller 흐름과 활용

2025. 1. 28. 15:05·🗄️ Backend/Spring

Spring Boot를 이용해 웹 애플리케이션이나 API 서버를 개발하다 보면, 다양한 계층(layer)과 개념을 마주하게 됩니다. 특히 Entity, DTO, Repository, Service, Controller는 가장 기본적이면서도 필수적인 구성 요소입니다.
이 글에서는 이 다섯 가지의 역할과 상호 연관관계 전 과정의 흐름을 파악할 수 있도록 구성했습니다.


목차

  1. Entity: DB 테이블과 1:1 매핑되는 핵심 도메인 객체
  2. DTO: 계층 간 데이터 전송을 위한 객체
  3. Repository: DB 접근 로직을 담당하는 계층
  4. Service: 비즈니스 로직을 담당하는 계층
  5. Controller: 웹 요청/응답을 처리하는 계층
  6. 전체 흐름과 연관관계
  7. 예시 프로젝트 구조
  8. 실전 예제 코드
  9. 마무리 및 정리

1. Entity

개념

  • Entity는 데이터베이스 테이블과 직접적으로 매핑되는 도메인(모델) 객체입니다.
  • Spring Data JPA를 사용할 때는 @Entity 어노테이션으로 선언하며, 테이블명이나 PK 등을 지정할 수 있습니다.
  • 실제 DB의 컬럼과 매핑되어, DB 저장/조회가 이루어집니다.

특징

  • DB와 1:1 매핑 → 테이블 구조를 반영해야 함
  • @Id로 기본 키(PK) 설정
  • Lombok(@Data, @Getter, @Setter)을 활용하면 보일러플레이트 코드가 줄어듦
  • 가급적 순수한 비즈니스 로직을 넣지 않는 것이 일반적이며, 데이터 상태를 표현하는 역할

예시 코드

package com.example.demo.entity;

import jakarta.persistence.*;
import lombok.*;

@Entity
@Table(name = "member") // DB의 테이블명
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class Member {
    
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY) // 자동 증가
    private Long id;

    @Column(nullable = false, length = 50)
    private String username;
    
    @Column(nullable = false)
    private int age;

    // 필요에 따라 다른 필드나 연관관계 매핑을 추가
}

위 Member 클래스는 DB의 member 테이블과 매핑되어 있으며, 각 컬럼에 해당하는 필드가 선언되어 있습니다.


2. DTO (Data Transfer Object)

개념

  • DTO는 '계층 간 데이터 전송'을 목적으로 하는 객체입니다.
  • Controller → Service → Repository로 넘어가는 과정에서 필요한 정보만 추출하여 옮기거나, 응답으로 전달할 때 Entity와 구분된 객체를 사용하는 것을 권장합니다.
  • Entity를 그대로 외부로 반환하면, 불필요한 정보 노출 또는 DB 스키마 변화에 따른 영향이 발생할 수 있습니다. DTO를 사용하면 이러한 문제를 예방할 수 있습니다.

특징

  • 순수하게 데이터 교환만을 위한 클래스이므로, 비즈니스 로직은 넣지 않는 것이 일반적
  • @Data(Lombok) 등을 사용해 간단히 만들 수 있음
  • API 요청/응답 형식 그대로 작성 가능

예시 코드

package com.example.demo.dto;

import lombok.*;

@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class MemberDTO {
    private Long id;
    private String username;
    private int age;
}

MemberDTO는 예시일 뿐이며, 실제로는 요청용 DTO와 응답용 DTO를 분리하기도 합니다.
예: MemberRequestDTO, MemberResponseDTO


3. Repository

개념

  • Repository는 DB에 접근하는 로직을 담당하는 계층입니다.
  • Spring Data JPA 기준 JpaRepository(또는 CrudRepository)를 상속받아 사용합니다.
  • 보통 Entity와 쌍을 이뤄 구성하며, @Repository 어노테이션을 사용합니다. (@Repository는 선택적, JpaRepository 상속 시 자동 인식)

특징

  • CRUD(Create, Read, Update, Delete) 작업을 메서드로 간단히 제공
  • 복잡한 쿼리나 조건이 필요하다면, Query 메서드나 @Query를 사용해 직접 작성 가능
  • 비즈니스 로직은 넣지 않고, 데이터 엑세스에만 집중

예시 코드

package com.example.demo.repository;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import com.example.demo.entity.Member;

@Repository
public interface MemberRepository extends JpaRepository<Member, Long> {
    // findBy, countBy 등 Spring Data JPA 규칙에 맞춘 메소드 생성 가능
    // 예: List<Member> findByUsername(String username);
}

MemberRepository는 Member 엔티티를 기반으로 한 DB 접근 로직을 담당합니다.


4. Service

개념

  • Service는 핵심적인 비즈니스 로직을 담당하는 계층입니다.
  • 여러 Repository를 조합하거나, 다수의 처리를 연결해 업무 로직을 구성합니다.
  • 트랜잭션(@Transactional)을 통해 원자적인 작업 단위를 보장합니다.

특징

  • Controller가 Service 메서드를 호출하면, Service는 필요한 Repository를 호출하여 DB에 접근
  • DTO ↔ Entity 변환(매핑) 로직을 넣는 경우도 많음 (혹은 별도 Mapper를 둘 수도 있음)
  • 재사용 가능하도록 메소드 단위로 비즈니스 로직을 잘게 나누기도 함

예시 코드

package com.example.demo.service;

import com.example.demo.dto.MemberDTO;
import com.example.demo.entity.Member;
import com.example.demo.repository.MemberRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

@Service
@RequiredArgsConstructor
public class MemberService {

    private final MemberRepository memberRepository;

    // 회원가입 로직
    public MemberDTO createMember(MemberDTO dto) {
        // 1. DTO를 Entity로 변환
        Member member = Member.builder()
                .username(dto.getUsername())
                .age(dto.getAge())
                .build();

        // 2. DB 저장
        Member savedMember = memberRepository.save(member);

        // 3. 저장된 결과를 다시 DTO로 변환
        return MemberDTO.builder()
                .id(savedMember.getId())
                .username(savedMember.getUsername())
                .age(savedMember.getAge())
                .build();
    }

    // 단일 회원 조회 예시
    public MemberDTO getMember(Long id) {
        Member member = memberRepository.findById(id)
                .orElseThrow(() -> new RuntimeException("Member Not Found"));

        return MemberDTO.builder()
                .id(member.getId())
                .username(member.getUsername())
                .age(member.getAge())
                .build();
    }

    // 필요에 따라 목록 조회, 수정, 삭제 등 다양한 메서드 추가
}

MemberService는 DTO와 Entity 간의 변환을 한 뒤 저장/조회하며, 필요한 비즈니스 로직(예: 유효성 검사, 예외 처리 등)을 추가할 수 있습니다.


5. Controller

개념

  • Controller는 클라이언트(웹/앱)의 요청을 받고, 응답을 반환하는 계층입니다.
  • HTTP 요청을 받는 메서드에 @RestController, @RequestMapping, @GetMapping, @PostMapping 등으로 REST API를 매핑합니다.
  • 사용자 입력 데이터를 DTO로 받고, Service를 통해 처리 후, 응답 DTO 또는 기타 객체를 반환합니다.

특징

  • 주로 요청/응답 처리에만 집중: 비즈니스 로직은 최대한 Service에 위임
  • Request Body → DTO 변환, Response Body → DTO 변환
  • Swagger 등 API 문서화 도구와 연계되는 가장 앞단

예시 코드

package com.example.demo.controller;

import com.example.demo.dto.MemberDTO;
import com.example.demo.service.MemberService;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/api/members")
@RequiredArgsConstructor
public class MemberController {

    private final MemberService memberService;

    // 회원 가입
    @PostMapping
    public MemberDTO createMember(@RequestBody MemberDTO memberDTO) {
        return memberService.createMember(memberDTO);
    }

    // 회원 단일 조회
    @GetMapping("/{id}")
    public MemberDTO getMember(@PathVariable Long id) {
        return memberService.getMember(id);
    }

    // 필요에 따라 목록 조회, 수정, 삭제 등 Endpoint 추가
}

MemberController는 외부에서 /api/members URL로 들어오는 HTTP 요청을 처리합니다.
예) POST /api/members → createMember()


6. 전체 흐름과 연관관계

간단히 흐름을 요약하면 다음과 같습니다.

  1. Controller: 클라이언트 요청을 받아 DTO 형태로 입력을 받음
  2. Service: Controller로부터 받은 DTO를 검증·가공하고, Repository를 통해 DB를 액세스
  3. Repository: DB와 직접 연결되어 CRUD 실행. Entity를 주고받음
  4. Entity: DB 테이블과 1:1 매핑된 객체. Repository에서 사용됨
  5. Service(다시): Entity를 DTO로 변환 후 Controller에 반환
  6. Controller: 최종적으로 DTO를 응답으로 만들어 클라이언트에게 보냄

7. 예시 프로젝트 구조

프로젝트 구조 예시(패키지 기준):

src
 ┣ main
 ┃ ┣ java
 ┃ ┃ ┗ com.example.demo
 ┃ ┃ ┃ ┣ controller
 ┃ ┃ ┃ ┃ ┗ MemberController.java
 ┃ ┃ ┃ ┣ dto
 ┃ ┃ ┃ ┃ ┗ MemberDTO.java
 ┃ ┃ ┃ ┣ entity
 ┃ ┃ ┃ ┃ ┗ Member.java
 ┃ ┃ ┃ ┣ repository
 ┃ ┃ ┃ ┃ ┗ MemberRepository.java
 ┃ ┃ ┃ ┣ service
 ┃ ┃ ┃ ┃ ┗ MemberService.java
 ┃ ┃ ┃ ┗ DemoApplication.java
 ┃ ┗ resources
 ┃   ┗ application.properties
 ┗ ...
  1. controller 패키지 → Controller 클래스
  2. service 패키지 → Service 클래스
  3. repository 패키지 → Repository 인터페이스
  4. entity 패키지 → Entity 클래스
  5. dto 패키지 → DTO 클래스

8. 실전 예제 코드

위에서 보여준 코드들을 종합하면 다음과 같은 예제가 완성됩니다.

Member Entity

@Entity
@Table(name = "member")
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class Member {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(nullable = false, length = 50)
    private String username;

    @Column(nullable = false)
    private int age;
}

MemberDTO

@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class MemberDTO {
    private Long id;
    private String username;
    private int age;
}

MemberRepository

@Repository
public interface MemberRepository extends JpaRepository<Member, Long> {
    // 추후 커스텀 쿼리나 메서드 추가 가능
}

MemberService

@Service
@RequiredArgsConstructor
public class MemberService {
    private final MemberRepository memberRepository;

    public MemberDTO createMember(MemberDTO dto) {
        Member member = Member.builder()
                .username(dto.getUsername())
                .age(dto.getAge())
                .build();

        Member savedMember = memberRepository.save(member);

        return MemberDTO.builder()
                .id(savedMember.getId())
                .username(savedMember.getUsername())
                .age(savedMember.getAge())
                .build();
    }

    public MemberDTO getMember(Long id) {
        Member member = memberRepository.findById(id)
                .orElseThrow(() -> new RuntimeException("Member Not Found"));

        return MemberDTO.builder()
                .id(member.getId())
                .username(member.getUsername())
                .age(member.getAge())
                .build();
    }
}

MemberController

@RestController
@RequestMapping("/api/members")
@RequiredArgsConstructor
public class MemberController {
    private final MemberService memberService;

    @PostMapping
    public MemberDTO createMember(@RequestBody MemberDTO memberDTO) {
        return memberService.createMember(memberDTO);
    }

    @GetMapping("/{id}")
    public MemberDTO getMember(@PathVariable Long id) {
        return memberService.getMember(id);
    }
}

9. 마무리 및 정리

  • Entity는 DB 테이블과 매핑되는 객체, DTO는 계층 간 데이터 전송을 위한 객체
  • Repository는 DB 접근 로직, Service는 비즈니스 로직, Controller는 HTTP 요청/응답을 다룸
  • 이 다섯 요소가 협력하여 Spring Boot 애플리케이션이 동작하며, 계층별 책임을 명확히 분리하면 유지보수와 확장성이 크게 향상됩니다.
  • 실제로는 @Transactional, 예외 처리, 로그 처리, ModelMapper를 활용한 자동 매핑 등 더 많은 기술을 적용할 수 있습니다. 하지만 이번 글에서는 전형적인 Spring Boot의 기본 구조를 이해하는 데 초점을 맞췄습니다.

이 글은 사이드 프로젝트를 진행하며 , 복습 및 리마인드를 위해 작성한 게시글입니다.

 

 

'🗄️ Backend > Spring' 카테고리의 다른 글

Spring과 Spring Boot의 차이점  (1) 2025.02.08
SpringBoot 비동기(Async) 처리  (6) 2025.01.17
Spring Boot 기초: 웹 애플리케이션 설정  (0) 2024.11.10
HikariCP, MyBatis를 활용한 데이터베이스 연결 풀 설정 및 최적화  (1) 2024.11.10
스프링 프레임워크에서 Redirect, Request, Response 처리 및 서비스 계층 구현  (8) 2024.11.09
'🗄️ Backend/Spring' 카테고리의 다른 글
  • Spring과 Spring Boot의 차이점
  • SpringBoot 비동기(Async) 처리
  • Spring Boot 기초: 웹 애플리케이션 설정
  • HikariCP, MyBatis를 활용한 데이터베이스 연결 풀 설정 및 최적화
hjwjo
hjwjo
백엔드 및 풀스택 개발에 관심 있는 초보 개발자의 개발 블로그입니다.
  • hjwjo
    Jeongwoo's Devlog
    hjwjo
  • 전체
    오늘
    어제
    • Devlog
      • 🗄️ Backend
        • Java
        • Spring
        • JPA
        • SQL
        • JSP
        • AWS
        • GCP
        • Linux
        • GitHub
        • ML
        • Security
      • 🖥️ Frontend
        • React
        • CSS
      • 🏅 Project
        • Hackathon
        • Team Project
      • 📊 Algorithm
        • BOJ
      • 📜 Certs
        • ADsP
        • SQLD
        • 정보처리기사
      • 📖
        • JavaScript
      • 일상
        • 면접후기
  • 블로그 메뉴

    • 홈
    • Devlog
    • 태그
    • 방명록
  • 링크

    • GitHub
  • 공지사항

  • 인기 글

  • 태그

    쿼리
    AWS
    정처기
    GCP
    java
    SQL
    데이터베이스
    java기초
    Spring
    스프링부트
    스프링
    자바
    DML
    jsp
    정보처리기사
    ADsP
    http
    백준
    springboot
    백엔드
  • 최근 댓글

  • 최근 글

hjwjo
Spring Boot 아키텍처 : Entity, DTO, Repository, Service, Controller 흐름과 활용
상단으로

티스토리툴바