보통 프로젝트를 할 때 MVC 패턴으로 개발을 하는데, 이는 역할을 분리하여 개발한다는 것이다.
이렇게 해야 유지보수가 쉽고 Controller, Model, View를 독립적으로 개발할 수 있어 확장성이 높기 때문인데, 일단 MVC가 무엇인지 알아야 효율적으로 개발을 할 수 있으니 MVC가 무엇인지 알아보도록 하자!
소프트웨어 아키텍처 패턴 중 하나로, 애플리케이션의 역할을 Model-View-Controller 3가지로 분리하여 유지보수와 확장성을 높이는 구조
Spring Boot에서 기본적으로 MVC패턴을 사용해서 웹 애플리케이션을 개발한다.
Spring MVC의 동작 과정
- 사용자가 요청(URL 요청)
- DispatcherServlet(프론트 컨트롤러)가 요청을 가로챔
- 요청을 적절한 Controller에게 전달
- Controller는 요청을 처리하고, 필요한 데이터를 Service를 통해 조회
- Service는 데이터베이스와 연동되는 Repository를 호출
- Repository가 MySQL 등의 DB와 연결하여 데이터 조회 및 처리
- 조회한 데이터를 Model에 담아서 View(Thymeleaf)로 전달
- Thymeleaf 템플릿 엔진이 데이터를 화면에 렌더링
- 완성된 HTML이 사용자에게 응답으로 반환됨
아직 잘 이해가 되지 않을테니 밑에서 더 알아보도록 하자
먼저 MVC란, 애플리케이션을 Model(모델) - View(뷰) - Controller(컨트롤러) 3가지 역할로 나누어 개발하는 구조를 말한다.
가장 먼저 Model에 대해 알아보자.
Model (모델)
- 데이터를 처리하는 역할로, 데이터베이스와 연결되어 데이터를 저장하고 가공한다.
- MVC 패턴에서 Model은 애플리케이션의 데이터를 다루는 모든 로직을 포함하는데,
Entity와 DTO, Service, Repository가 포함된다.
개념
- 데이터베이스의 테이블과 1:1 매핑되는 클래스이며 @Entity 어노테이션을 사용하여 정의한다.
- 데이터 저장, 조회, 수정, 삭제 등을 수행하는 객체 자체이며 일반적으로 Service나 Repository에서 사용된다.
쉽게 말해 데이터베이스에 테이블, 즉 데이터가 있을 때, 우리는 작성한 클래스 위에 @Entity라는 어노테이션을 붙여서 이 클래스가 엔티티이고 해당 테이블과 매핑된다! 라고 선언해주는 것이다.
비즈니스 로직이 포함되지 않고, 데이터 자체를 표현하는 것이 목적이다!
import jakarta.persistence.*;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
@Entity
@Table(name = "users")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private String email;
private String password;
}
예시 코드를 보면 @Entity 어노테이션으로 선언해준 것을 알 수 있다.
개념
- Entity를 이용해 데이터베이스와 직접 소통하는 계층이다.
- 데이터를 저장, 조회, 수정, 삭제(CRUD)하는 역할이며 Spring Data JPA를 사용하면 SQL을 직접 작성하지 않아도 자동으로 처리된다.
즉, Respository는 JPA를 사용하여 DB에 접근, 직접 상호작용하는 계층이며 Entity를 다루게 된다.
import org.springframework.data.jpa.repository.JpaRepository;
public interface UserRepository extends JpaRepository<User, Long> {
// JpaRepository<User, Long>을 상속하면 기본 CRUD 메서드를 자동 생성
}
기본으로 제공되는 메서드는 다음과 같다.
📍 기본 제공 메서드
save(User user) : 사용자 저장
findById(Long id) : 특정 사용자 조회
findAll() : 모든 사용자 조회
deleteById(Long id) : 특정 사용자 삭제
count() : 총 사용자 수 반환
개념
- 비즈니스 로직을 처리하는 계층이다.
- Repository를 통해 데이터베이스에서 값을 조회하거나, 가공하여 Controller에 전달한다.
- 여러 Repository를 조합하여 복잡한 로직을 수행 가능
즉, Controller와 Repository의 중간 통로 역할을 한다고 생각하면 된다.
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.stream.Collectors;
@Service
public class UserService {
private final UserRepository userRepository;
public UserService(UserRepository userRepository) {
this.userRepository = userRepository;
}
// 모든 사용자 조회 (Entity → DTO 변환)
public List<UserDTO> getAllUsers() {
return userRepository.findAll()
.stream()
.map(user -> new UserDTO(user.getName(), user.getEmail()))
.collect(Collectors.toList());
}
// 사용자 저장 (DTO → Entity 변환)
public void saveUser(UserDTO userDTO) {
User user = new User();
user.setName(userDTO.getName());
user.setEmail(userDTO.getEmail());
user.setPassword("defaultPassword"); // 실제 환경에서는 암호화 필요
userRepository.save(user);
}
}
개념
- 계층 간 데이터 전송을 위해 사용하는 객체이다.
- Entity와 달리 DB와 직접적인 연동이 없고, 필요한 데이터만 포함한다.
- Entity의 민감한 정보를 숨기거나, 가공된 데이터를 전송하는 역할이다.
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
@Getter
@Setter
@NoArgsConstructor
public class UserDTO {
private String name;
private String email;
public UserDTO(String name, String email) {
this.name = name;
this.email = email;
}
}
Entity 중 민감하지 않은 정보만 뽑아 정보를 전송하는 클래스라고 생각하면 된다.