반응형
SMALL
스프링 프레임워크를 경험하면 한 번씩은 들어본 MVC 패턴에 대해서 기록하려고 한다.
MVC 패턴은 애플리케이션의 유지보수성과 확장성을 높이기 위해 UI와 비즈니스 로직을 분리하는 아키텍처 패턴이다.
Counter 앱을 예제로 어떻게 구현이 되는지 작성하려고 한다.
서론
MVC 패턴이란?
MVC (Model-View-Controller) 패턴은 애플리케이션을 Model, View, Controller 세 가지 구성 요소로 나누어 각 컴포넌트가 독립적으로 동작하도록 구조화한 아키텍처 패턴이다.
- Model: 데이터와 비즈니스 로직을 관리하는 부분
- View: 사용자에게 보여지는 UI
- Controller: Model과 View를 중개하며, 사용자의 요청을 처리하고 응답을 생성
스프링 MVC 패턴을 사용하면 비즈니스 로직과 UI를 분리하여 코드의 유지보수성과 확장성을 높일 수 있다.
본론
MVC 패턴을 사용하는 이유
UI와 비즈니스 로직을 분리함으로써 개발 효율성과 유지보수성을 높여준다.
예를 들어 UI를 수정해도 Model이나 Controller에 영향을 미치지 않는다. 또한, 비즈니스 로직이나 데이터 처리 로직을 쉽게 변경할 수 있어 코드 수정이 필요할 때 영향을 최소화할 수 있다.
MVC 패턴의 장점
- 코드의 분리: UI와 비즈니스 로직이 분리되어 코드가 구조적
- 유지보수성: 각 컴포넌트가 독립적이므로, 특정 부분을 수정해도 다른 부분에 영향을 주지 않는다.
- 확장성: MVC가 독립적이므로 애플리케이션 확장하기 쉽다.
MVC 패턴의 단점
- 복잡성 증가: 간단한 애플리케이션에서는 MVC 구조가 오히려 복잡성을 증가시킬 수 있다.
- 테스트 용이성: Controller와 View 간의 강한 의존성으로 인해 테스트가 어려워질 수 있다.
예제: Counter 프로그램
스프링 MVC 패턴을 활용하여 간단한 Counter 앱을 구현하였다. 이 앱은 버튼을 클릭하여 숫자를 증감시키는 기능을 제공하며, 데이터 관리를 위해 Repository 계층도 구현하였다.
Controller
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
@Controller
public class CounterController {
private final CounterService counterService;
@Autowired
public CounterController(CounterService counterService) {
this.counterService = counterService;
}
// 카운터 페이지 보여주기
@GetMapping("/counter")
public String showCounter(Model model) {
model.addAttribute("count", counterService.getCount());
return "counter";
}
// 카운트 증가
@PostMapping("/counter/increment")
public String incrementCounter() {
counterService.increment();
return "redirect:/counter";
}
// 카운트 감소
@PostMapping("/counter/decrement")
public String decrementCounter() {
counterService.decrement();
return "redirect:/counter";
}
}
- @Controller로 정의되어 요청을 받아 처리한다.
- /counter 경로로 GET 요청을 받으면 showCounter 메서드가 호출되어 현재 카운트 값을 Model에 담아 View에 전달
- /counter/increment와 /counter/decrement 경로로 POST 요청을 받으면 카운트 값을 증가하거나 감소시킨 후 /counter로 리다이렉트 하여 결과를 갱신한다.
Service
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class CounterService {
private final CounterRepository counterRepository;
@Autowired
public CounterService(CounterRepository counterRepository) {
this.counterRepository = counterRepository;
}
// 현재 카운트 값을 반환
public int getCount() {
return counterRepository.getCounter().getCount();
}
// 카운트를 증가시키는 메서드
public void increment() {
CounterModel counter = counterRepository.getCounter();
counter.setCount(counter.getCount() + 1);
counterRepository.saveCounter(counter);
}
// 카운트를 감소시키는 메서드
public void decrement() {
CounterModel counter = counterRepository.getCounter();
counter.setCount(counter.getCount() - 1);
counterRepository.saveCounter(counter);
}
}
- @Service로 정의되어 비즈니스 로직을 처리하며, CounterRepository를 통해 데이터를 접근
- increment와 decrement 메서드를 통해 카운터 값을 증감시키고, 변경된 값을 Repository에 저장
Repository
import org.springframework.stereotype.Repository;
@Repository
public class CounterRepository {
private CounterModel counter = new CounterModel(0); // 초기값 설정
// 카운터 값을 반환
public CounterModel getCounter() {
return counter;
}
// 카운터 값을 저장 (현재 예제에서는 메모리 상에 저장)
public void saveCounter(CounterModel counter) {
this.counter = counter;
}
}
- @Repository로 정의되어 데이터 관리 역할을 수행
- 카운트 값을 메모리에 저장하며, 실제 환경에서는 데이터베이스와 연동하여 영속적 저장 가능
Model
public class CounterModel {
private int count;
public CounterModel(int count) {
this.count = count;
}
public int getCount() {
return count;
}
public void setCount(int count) {
this.count = count;
}
}
- 카운트 값을 저장하는 간단한 데이터 클래스
- get, set 메서드를 통해 카운트 값을 읽고 쓸 수 있다. Lombok 디펜던시를 추가하여 어노테이션으로 처리도 가능
View
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>Counter App</title>
</head>
<body>
<h1>Counter: <span th:text="${count}">0</span></h1>
<form th:action="@{/counter/increment}" method="post">
<button type="submit">Increment</button>
</form>
<form th:action="@{/counter/decrement}" method="post">
<button type="submit">Decrement</button>
</form>
</body>
</html>
- counter.html은 Thymeleaf 템플릿을 사용하여 View를 구성
- count 값은 th:text="${count}"를 통해 Controller에서 전달된 값을 표시
- Increment와 Decrement 버튼은 각각 /counter/increment와 /counter/decrement 경로로 POST 요청을 보내어 Controller에서 처리
결론
MVC 패턴을 통해 애플리케이션을 Model, View, Controller로 분리하여 UI와 비즈니스 로직을 독립적으로 관리할 수 있다. 스프링 프레임워크는 이러한 패턴을 쉽게 구현할 수 있는 다양한 어노테이션과 기능을 제공하여 개발 생산성을 높여준다.
반응형
LIST
'Backend > Spring || SpringBoot' 카테고리의 다른 글
[Spring || SpringBoot] Controller와 RestController 란? (2) | 2024.12.29 |
---|---|
[Spring || SpringBoot] Thymeleaf Layout - 타임리프 레이아웃 적용 하기 (1) | 2024.09.09 |
[Spring || SpringBoot] IPv4 설정 (0) | 2024.09.09 |
[Spring || SpringBoot] Spring에서 @Value로 Properties 값 가져오기 (0) | 2024.09.09 |
[Spring || SpringBoot] Rest API 공통 Response 포맷 구현 (1) | 2024.03.25 |