Spring 웹 애플리케이션 계층구조

계층구조

Spring 에서 웹 애플리케이션을 만들 때, 코드를 체계적으로 관리하기 위해 계층 구조를 사용합니다.

이 구조는 역할에 따라 프로그램을 세 부분으로 나누는 방식으로, 우리가 건물을 지을 때 기초, 벽, 지붕처럼 각각의 역할을 나눈 것과 비슷하다고 생각하시면 됩니다.

 

개발자 입장에서는 이렇게 세분화함으로써 효율적으로 개발을 하고자 함인데요, 기본적인 계층으로는 크게 컨트롤러, 서비스, 리포지토리, DTO, 모델등으로 구성되어 있습니다.

 

각각의 계층은 계층마다 독립적으로 분리하여 구현하는것이 가능해야하고, 각 계층에서 담당해야 할 기능들이 있습니다.

 

 

계층

컨트롤러 ( Controller )

컨트롤러 계층은 HTTP 요청을 받아들이는 진입점입니다.

클라이언트의 요청에 따라 어떤 처리를 할지 결정하고, 요청에 맞는 서비스 메소드를 호출합니다. 

컨트롤러는 주로 @Controller 또는 @RestController 어노테이션을 사용하여 정의됩니다. 

@RestController 는 JSON 형태로 객체 데이터를 반환하기 위해 사용합니다.

 

서비스 ( Service )

프로젝트의 비즈니스 로직을 책임지는 계층입니다.

컨트롤러로부터 받은 요청을 실제로 실행하는 역할을 하며, 여러 DAO( Data Access Object ) 또는 리포지토리와 협력하여 데이터를 처리합니다. 서비스 계층은 재사용 가능한 비즈니스 로직의 집합으로, 애플리케이션의 핵심 기능을 구현합니다.

리포지토리 ( Repository )

내 애플리케이션과 DB 간의 연동을 책임지는 부분입니다.

스프링 데이터 JPA, MyBatis 등을 사용하여 데이터베이스의 CRUD 연산을 추상화합니다.

@Repository 어노테이션을 사용하여 리포지토리 인터페이스를 정의하면, 스프링이 구현체를 자동으로 생성하여 관리합니다.

DTO ( Data Transfer Object )

계층 간 데이터 교환을 위해 사용되는 객체입니다. 컨트롤러와 서비스 계층, 또는 서비스와 리포지토리 계층 사이에서 데이터를 전달할 때 사용됩니다. DTO 를 사용하여 불필요한 데이터 전송을 줄이고, 각 계층이 필요한 데이터만을 받도록 할 수 있습니다.

모델 ( Model )

모델은 애플리케이션에서 사용되는 데이터와 비즈니스 로직을 포함합니다.

스프링MVC 에서는 컨트롤러와 뷰 사이에서 데이터를 전달하는 데 사용되는 객체를 의미하기도 합니다.

컨트롤러에서 모델 객체를 뷰에 전달하여, 뷰가 사용자에게 보여줄 데이터를 구성할 수 있습니다.

 

 

예시

아래에 나오는 예시 코드들은 위에서 공부한 내용을 바탕으로 컨트롤러, 서비스, 리포지토리, DTO, 모델을 사용하는 예제입니다.

 

모델 ( Model )

모델은 데이터베이스와 매핑되는 실제 데이터 구조를 정의합니다.

@Entity // 데이터베이스 테이블과 매핑
public class User {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY) // 기본 키 (자동 증가)
    private Long id;

    private String name; // 사용자 이름
    private String email; // 사용자 이메일

    public User() {} // 기본 생성자

    public User(String name, String email) {
        this.name = name;
        this.email = email;
    }

    // Getter와 Setter
    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }
}

 

DTO ( Data Transfer Object )

DTO 는 컨트롤러와 서비스, 또는 서비스와 리포지토리 사이에서 데이터를 전달합니다.

public class UserDto {

    private Long id; // 사용자 ID
    private String name; // 사용자 이름

    public UserDto(Long id, String name) {
        this.id = id;
        this.name = name;
    }

    // Getter와 Setter
    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

 

리포지토리 ( Repository )

리포지토리는 데이터베이스와의 통신을 담당합니다.

데이터를 가져오거나 저장할 때 사용되며, Spring Data JPA 를 사용하면 기본적은 CRUD 메서드를 제공받습니다.

@Repository // 데이터베이스와 연결되는 계층
public interface UserRepository extends JpaRepository<User, Long> {
    // JpaRepository는 findById, save 등의 CRUD 메서드를 기본 제공
}

 

서비스 ( Service )

서비스 계층은 비즈니스 로직을 처리합니다.

컨트롤러에서 받은 요청을 실제로 처리하며, 데이터를 가공하거나 조건을 추가합니다.

리포지토리를 호출해 데이터를 가져오거나 저장하며, 데이터를 DTO 로 변환하거나 추가 로직을 수행합니다.

@Service // 비즈니스 로직을 처리하는 서비스 계층임을 명시
public class UserService {

    private final UserRepository userRepository;

    public UserService(UserRepository userRepository) {
        this.userRepository = userRepository; // 리포지토리 계층을 주입받음
    }

    // ID로 사용자 조회
    public UserDto getUserById(Long id) {
        // 리포지토리 계층에서 사용자 엔티티를 가져옴
        User user = userRepository.findById(id)
                .orElseThrow(() -> new IllegalArgumentException("User not found: " + id));
        // 가져온 엔티티를 DTO로 변환하여 반환
        return new UserDto(user.getId(), user.getName());
    }

    // 사용자 생성
    public UserDto createUser(String name, String email) {
        // 새로운 사용자 엔티티 생성 후 리포지토리 계층에 저장
        User newUser = userRepository.save(new User(name, email));
        // 저장된 엔티티를 DTO로 변환하여 반환
        return new UserDto(newUser.getId(), newUser.getName());
    }
}

 

컨트롤러 ( Controller )

컨트롤러는 웹 애플리케이션의 진입점입니다.

사용자가 보낸 HTTP 요청을 받습니다.

요청의 내용을 해석하고, 이를 처리하기 위해 서비스 계층에 전달합니다.

서비스 계층에서 처리된 결과를 사용자에게 반환합니다.

@RestController // REST API를 처리하는 컨트롤러임을 명시
@RequestMapping("/users") // 기본 경로: /users
public class UserController {

    private final UserService userService;

    public UserController(UserService userService) {
        this.userService = userService; // 서비스 계층을 주입받음
    }

    // 사용자 조회 요청 처리
    @GetMapping("/{id}") // URL: /users/{id}
    public ResponseEntity<UserDto> getUser(@PathVariable Long id) {
        // 서비스 계층에 사용자 정보를 요청
        UserDto user = userService.getUserById(id);
        // 처리된 정보를 HTTP 응답으로 반환
        return ResponseEntity.ok(user); // 200 OK 상태로 JSON 데이터 반환
    }

    // 사용자 생성 요청 처리
    @PostMapping // URL: /users
    public ResponseEntity<UserDto> createUser(@RequestBody Map<String, String> userRequest) {
        // 요청 본문에서 이름과 이메일 추출
        String name = userRequest.get("name");
        String email = userRequest.get("email");
        // 서비스 계층에 사용자 생성 요청
        UserDto newUser = userService.createUser(name, email);
        // 처리된 정보를 HTTP 응답으로 반환 (201 Created 상태)
        return ResponseEntity.status(HttpStatus.CREATED).body(newUser);
    }
}

'Spring' 카테고리의 다른 글

Spring - @Value  (2) 2024.12.20
Spring Bean 을 등록하는 3가지 방법  (1) 2024.12.19
스프링 빈(Bean) 이란?  (1) 2024.12.16
Spring - 경로 변수  (0) 2024.12.12
[Spring MVC] - QueryString  (0) 2024.12.12