25.03.11 TIL Spring MVC 흐름

신성훈·2025년 3월 11일

TIL

목록 보기
145/162

1. Spring MVC란?

Spring MVC(Model-View-Controller)는 웹 애플리케이션 개발을 위한 프레임워크로 클라이언트 요청을 효과적으로 처리하고 응답을 반환하는 구조를 제공한다.
Spring MVC는 DispatcherServlet을 중심으로 요청을 처리하며 요청을 적절한 컨트롤러로 전달하고 응답을 생성하는 과정을 담당한다.


2. Spring MVC 요청 처리 흐름

Spring MVC에서 클라이언트의 요청이 처리되는 흐름은 다음과 같다.

  1. 클라이언트 요청(Request) 발생

    • 사용자가 웹 브라우저에서 URL을 입력하거나 API를 호출하면 요청이 발생한다.
  2. DispatcherServlet 수신

    • 요청이 들어오면 DispatcherServlet이 가장 먼저 요청을 받아 처리한다.
    • DispatcherServlet은 Spring의 Front Controller 역할을 한다.
  3. HandlerMapping을 통해 적절한 컨트롤러 찾기

    • DispatcherServlet은 요청 URL에 맞는 컨트롤러를 찾기 위해 HandlerMapping을 사용한다.
  4. Controller에서 요청 처리

    • 찾은 컨트롤러의 해당 메서드를 실행하여 요청을 처리한다.
  5. Service & Repository 호출 (비즈니스 로직 처리)

    • 컨트롤러는 필요한 경우 서비스 계층을 호출하고 서비스 계층은 데이터 처리를 위해 레포지토리를 호출한다.
    • 데이터베이스에서 필요한 데이터를 조회하거나 저장한다.
  6. ModelAndView 또는 Response 반환

    • 컨트롤러에서 처리된 결과를 ModelAndView(뷰 렌더링) 또는 ResponseEntity(API 응답) 형태로 반환한다.
  7. ViewResolver를 통해 View 결정

    • DispatcherServletViewResolver를 사용하여 적절한 View(JSP, Thymeleaf 등)를 찾는다.
    • API 요청의 경우 JSON 데이터를 반환한다.
  8. 클라이언트에게 응답 반환

    • 최종적으로 View를 렌더링하거나 JSON 형태로 응답을 반환한다.

3. Spring MVC의 핵심 컴포넌트

  1. DispatcherServlet

    • Spring MVC의 핵심으로 모든 요청을 받아 적절한 핸들러(컨트롤러)로 전달한다.
  2. HandlerMapping

    • 요청 URL과 컨트롤러를 매핑하는 역할을 한다.
  3. Controller

    • 요청을 처리하고 비즈니스 로직을 수행하는 역할을 한다.
  4. Service

    • 비즈니스 로직을 처리하는 계층으로 데이터 처리 및 연산을 담당한다.
  5. Repository (DAO)

    • 데이터베이스와의 연결을 담당하는 계층으로 JPA, MyBatis 등을 사용하여 데이터를 조회하거나 저장한다.
  6. ViewResolver

    • 컨트롤러에서 반환한 View 정보를 바탕으로 적절한 View(JSP, Thymeleaf 등)를 찾아 렌더링한다.
  7. ModelAndView

    • 컨트롤러에서 뷰(View)와 데이터를 함께 전달하는 객체이다.
  8. ResponseEntity

    • API 응답을 커스텀할 때 사용되는 객체로 HTTP 상태 코드와 함께 JSON 데이터를 반환할 수 있다.

4. Spring MVC 예제 코드

Controller 예제

@RestController
@RequestMapping("/users")
public class UserController {
    
    private final UserService userService;
    
    public UserController(UserService userService) {
        this.userService = userService;
    }

    // GET 요청 처리
    @GetMapping("/{id}")
    public ResponseEntity<User> getUser(@PathVariable Long id) {
        User user = userService.getUserById(id);
        return ResponseEntity.ok(user);
    }

    // POST 요청 처리
    @PostMapping
    public ResponseEntity<User> createUser(@RequestBody User user) {
        User savedUser = userService.createUser(user);
        return ResponseEntity.status(HttpStatus.CREATED).body(savedUser);
    }
}

Service 예제

@Service
public class UserService {
    
    private final UserRepository userRepository;
    
    public UserService(UserRepository userRepository) {
        this.userRepository = userRepository;
    }
    
    public User getUserById(Long id) {
        return userRepository.findById(id)
                .orElseThrow(() -> new RuntimeException("User not found"));
    }
    
    public User createUser(User user) {
        return userRepository.save(user);
    }
}

Repository 예제

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

Entity 예제

@Entity
public class User {
    
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;
    private String email;
    
}

5. 마무리

Spring MVC는 DispatcherServlet을 중심으로 요청을 처리하며 각 계층을 분리하여 유지보수성을 높이는 구조를 제공한다.
Spring MVC의 흐름을 정확히 이해하면 백엔드에서 요청이 어떻게 전달되고 어떻게 응답이 반환되는지를 명확하게 알 수 있다. @RequestMapping, @Controller, @Service, @Repository 같은 주요 어노테이션을 활용하여 효율적으로 애플리케이션을 구성할 수 있다.
앞으로 개발할 때 Spring MVC 구조를 잘 활용하여 유지보수성이 높은 코드를 작성하는 것이 중요하다는 점을 다시금 느꼈다.

profile
조급해하지 말고, 흐름을 만들고, 기록하면서 쌓아가자.

0개의 댓글