개발천재

[Spring Boot] MVC 패턴 이해하기 본문

개발 준비/Spring Boot

[Spring Boot] MVC 패턴 이해하기

세리블리 2025. 2. 14. 22:32
반응형

MVC 개념 이해하기

MVC는 모델(Model), 뷰(View), 컨트롤러(Controller) 세 가지 부분으로 나누어 개발하는 방법이다. 모델은 데이터를 저장하고 처리하는 부분, 뷰는 사용자가 볼 수 있는 화면을 구성하는 부분, 컨트롤러는 사용자의 요청을 받아서 모델과 뷰를 연결하고 처리하는 부분이다. 이렇게 세 가지 역할을 분리함으로써 코드가 더 깔끔하고, 유지보수가 쉽기 때문이다. 예를 들어, 웹사이트에서 회원가입 폼을 만들 때, 모델은 사용자의 정보를 저장하고, 뷰는 폼을 보여주며, 컨트롤러는 사용자가 입력한 정보를 받아서 저장하는 역할을 한다.

 

Model (모델)

Spring Boot에서는 주로 DTO(데이터 전송 객체)나 엔티티(Entity) 클래스를 사용하여 모델을 구현한다. 모델은 데이터와 비즈니스 로직을 처리합니다. 예를 들어, 데이터베이스와의 상호작용, 계산, 데이터 검증 등을 담당한다.
Spring Boot에서는 JPA(Java Persistence API)나 MyBatis와 같은 ORM(Object-Relational Mapping) 라이브러리를 사용하여 데이터를 관리한다.

// User 엔티티
@Entity
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String userName;
    private String password;
    // getters and setters
}

 

 

 

View (뷰)

뷰는 사용자 인터페이스(UI)를 나타내며, 화면에 표시되는 내용을 담당한다. Spring Boot에서는 Thymeleaf, JSP, FreeMarker 등의 템플릿 엔진을 사용하여 HTML 페이지를 동적으로 생성한다.

뷰는 컨트롤러가 전달한 모델 데이터를 화면에 표시한다. 예를 들어, 사용자의 정보를 HTML 테이블로 렌더링할 수 있다.

<table>
    <tr>
        <th>Username</th>
        <th>Password</th>
    </tr>
    <tr th:each="user : ${users}">
        <td th:text="${user.userName}"></td>
        <td th:text="${user.password}"></td>
    </tr>
</table>

 

 

 

Controller (컨트롤러)

컨트롤러는 사용자 요청을 처리하고, 그 결과를 모델과 연결하여 뷰에 전달하는 역할을 한다. Spring Boot에서는 @RestController와 @Controller 어노테이션을 사용하여 HTTP 요청을 처리하는 컨트롤러를 정의한다.

@GetMapping, @PostMapping, @PutMapping 등의 어노테이션을 사용하여 HTTP 메서드에 맞는 메서드를 정의한다.

@Controller
@RequestMapping("/users")
public class UserController {

    private final UserService userService;

    // Constructor injection
    public UserController(UserService userService) {
        this.userService = userService;
    }

    @GetMapping("/list")
    public String getAllUsers(Model model) {
        List<User> users = userService.getAllUsers();
        model.addAttribute("users", users);
        return "userList";  // userList.html 템플릿을 렌더링
    }

    @PostMapping("/create")
    public String createUser(@ModelAttribute User user) {
        userService.createUser(user);
        return "redirect:/users/list";
    }
}

 

 





Spring Boot에서의 MVC 흐름

1. 사용자가 요청을 보낸다

사용자가 /users/list URL을 요청한다고 가정해보자.

 


2. 컨트롤러가 요청을 처리한다

컨트롤러는 사용자의 요청을 받아 해당 로직을 처리한다. @GetMapping을 사용하여 요청을 받는다.

@Controller
@RequestMapping("/users")
public class UserController {

    private final UserService userService;

    public UserController(UserService userService) {
        this.userService = userService;
    }

    @GetMapping("/list")
    public String listUsers(Model model) {
        List<User> userList = userService.getAllUsers();  // 모델 데이터를 가져옴
        model.addAttribute("users", userList);  // 모델 데이터를 뷰로 전달
        return "userList";  // 뷰 이름 (Thymeleaf 템플릿)
    }
}



3. 모델이 데이터를 반환한다
모델(보통 Sevice)은 데이터를 처리하고 반환한다. 여기서는 UserService가 UserRepository를 호출하여 데이터를 가져온다.

@Service
public class UserService {

    private final UserRepository userRepository;

    public UserService(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

    public List<User> getAllUsers() {
        return userRepository.findAll();  // DB에서 사용자 목록을 가져옴
    }
}

 

 

 

4. 컨트롤러가 뷰에 모델 데이터를 전달한다

컨트롤러는 model.addAttribute()를 사용하여 데이터를 뷰에 전달한다. 여기서 users라는 이름으로 데이터를 전달하고, 이 데이터를 뷰에서 사용할 수 있게 된다.

@Controller
public class UserController {
    @GetMapping("/list")
    public String listUsers(Model model) {
        List<User> userList = userService.getAllUsers();
        model.addAttribute("users", userList);  // 'users'라는 이름으로 데이터를 전달
        return "userList";  // userList.html 템플릿을 사용
    }
}

 

 

 

5. 뷰가 화면을 렌더링한다.

뷰는 Thymeleaf와 같은 템플릿 엔진을 사용하여 데이터를 바탕으로 HTML을 렌더링한다. 여기서는 userList.html 파일을 사용한다.

<!-- userList.html -->
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>User List</title>
</head>
<body>
<h1>Users</h1>
<table>
    <thead>
        <tr>
            <th>ID</th>
            <th>Name</th>
        </tr>
    </thead>
    <tbody>
        <tr th:each="user : ${users}">
            <td th:text="${user.id}"></td>
            <td th:text="${user.name}"></td>
        </tr>
    </tbody>
</table>
</body>
</html>

 

 

 

6. 브라우저가 최종적으로 화면을 표시한다

브라우저는 Thymeleaf 템플릿 엔진을 통해 동적으로 생성된 HTML을 사용자에게 표시한다. 예를 들어, users 목록이 있으면 <table>로 출력된다.

 

 

전체적인 흐름 요약

사용자가 요청하면 그 요청을 Controller가 받는다. 그 후에 Controller는 필요한 비즈니스 로직을 처리하는 Service에 요청을 보낸다. 그리고 Service는 실제 데이터를 조회하거나 처리하는 Repository에 요청을 보낸다.

예를 들어, 사용자 리스트 조회한다고 가정하면, 
1. 사용자가 /users/list 페이지에 접속.
2. Controller가 /users/list 요청을 받아 Service에 요청.
3. Service가 Repository에 findAll() 호출.
4. Repository는 DB에서 사용자 데이터를 가져옴.
5. 데이터를 받은 Service는 Controller에 전달.
6. Controller는 그 데이터를 Model에 담아 Thymeleaf 템플릿에 전달.
7. Thymeleaf는 화면에 사용자 목록을 표시.

 

 

사용자 요청 → Controller
사용자가 요청하면, Controller가 그 요청을 받는다.

// 회원가입자 리스트 페이지에 보여주기
@GetMapping("/userList")
public String userList(Model model) {
    List<User> userList = userService.findAll();
    model.addAttribute("userList", userList);
    return "/users/userList";
}

 

 

Controller → Service
Controller는 비즈니스 로직을 처리하는 Service를 호출한다. 예를 들어, 회원 목록을 가져오거나, 회원을 삭제하는 등의 작업을 Service에 맡긴다.

@Override
    public List<User> findAll() {
        return userRepository.findAll();
    }

 

 

Service → Repository
Service는 데이터를 처리하는 Repository에 요청을 보낸다. 예를 들어, findAll() 같은 메서드를 호출하여 DB에서 데이터를 가져오거나, save()로 데이터를 저장한다.

@Override
    public List<User> findAll() {
        List<User> userList = new ArrayList<>(userStore.values());
        return userList;
    }

 

 

Repository → DB
Repository는 DB와 직접 연결되어 있다. 그래서 DB에서 데이터를 가져오거나 저장하는 역할을 담당한다.

 

Repository → Service → Controller
Repository에서 데이터를 받아오면, 그 결과를 Service가 처리하고, 다시 Controller로 전달한다.

 

Controller → Model → View (Thymeleaf)
Controller는 Model에 데이터를 담아 Thymeleaf 템플릿으로 전달하고, 템플릿에서 화면에 데이터를 보여준다.

<table border="1">
    <thead>
    <tr>
        <th>No</th>
        <th>id</th>
        <th>nickname</th>
        <th>삭제</th>
        <th>수정</th>
    </tr>
    </thead>
    <tbody>
    <tr th:each="user, x : ${userList}">
        <td th:text="${x.index + 1}"></td>
        <td th:text="${user.userId}"></td>
        <td th:text="${user.nickName}"></td>
        <td>
            <a th:href="@{/users/delete/{id}(id=${user.userId})}"
               th:if="${user.userId !=null}"
               onclick="return confirn('정말 삭제하시겠습니까?')">
                <button>삭제</button>
            </a>
        </td>
        <td>
            <a th:href="@{/users/update/{id}(id=${user.userId})}">
                <button>수정</button>
            </a>
        </td>
    </tr>
    <th:block th:if="${#lists.isEmpty(userList)}">
        <tr colspan="5">데이터가 없습니다.</tr>
    </th:block>
    </tbody>
</table>
반응형