개발인생/Backend

[Spring] MVC 구조 설명 | Controller, Service, Repository로 역할 분리하기

forri 2025. 2. 25. 20:05

왜 MVC 패턴을 써야 할까?

웹 애플리케이션을 만들 때 비즈니스 로직 (데이터 처리), 화면 처리 (UI), 사용자 입력 처리 등을 한 곳에서 관리하면 유지보수가 어렵고 코드가 복잡해짐.
👉 이를 해결하기 위해 Model-View-Controller(MVC) 패턴을 사용해 역할을 분리하면 유지보수를 쉽게 할 수 있음.


✔️예제

[MVC가 없는 코드 (문제점)]

예제: 사용자가 "상품 목록 보기" 버튼을 클릭하면 상품 목록이 표시되는 기능

@WebServlet("/products")
public class ProductServlet extends HttpServlet {
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        // 1. 데이터베이스에서 상품 목록 가져오기 (비즈니스 로직)
        List<Product> products = new ArrayList<>();
        products.add(new Product(1, "노트북", 1500000));
        products.add(new Product(2, "스마트폰", 800000));

        // 2. HTML 코드 직접 작성 (뷰 + 컨트롤러 + 모델 혼합)
        response.setContentType("text/html");
        PrintWriter out = response.getWriter();
        out.println("<html><body>");
        out.println("<h1>상품 목록</h1>");
        out.println("<ul>");
        for (Product product : products) {
            out.println("<li>" + product.getName() + " - " + product.getPrice() + "원</li>");
        }
        out.println("</ul>");
        out.println("</body></html>");
    }
}
 

🚨 문제점

  1. 비즈니스 로직, UI, 컨트롤러가 한 곳에 섞여 있음
    → 유지보수 어려움, UI 변경 시 코드 전체를 수정해야 함.
  2. 데이터 처리 로직이 직접 Servlet에 있음
    → 데이터 접근 로직을 변경하면 여러 곳을 수정해야 함.
  3. 확장성 부족
    → API로 제공하거나 다른 UI로 바꿀 때 수정이 어려움.

✅ [MVC 패턴 적용한 코드]

👉 역할을 분리하여 유지보수성과 확장성을 높임

1️⃣ Model (데이터 관리)

public class Product {
    private int id;
    private String name;
    private int price;

    public Product(int id, String name, int price) {
        this.id = id;
        this.name = name;
        this.price = price;
    }

    public int getId() { return id; }
    public String getName() { return name; }
    public int getPrice() { return price; }
}

2️⃣ Repository (데이터 접근 계층)

import java.util.ArrayList;
import java.util.List;

public class ProductRepository {
    public List<Product> getAllProducts() {
        List<Product> products = new ArrayList<>();
        products.add(new Product(1, "노트북", 1500000));
        products.add(new Product(2, "스마트폰", 800000));
        return products;
    }
}

3️⃣ Controller (사용자 요청 처리)

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import java.util.List;

@Controller
public class ProductController {
    private final ProductRepository productRepository = new ProductRepository();

    @GetMapping("/products")
    public String showProductList(Model model) {
        List<Product> products = productRepository.getAllProducts();
        model.addAttribute("products", products);
        return "product-list"; // View 이름 반환
    }
}

4️⃣ View (화면, HTML)

📂 src/main/resources/templates/product-list.html

<!DOCTYPE html>
<html>
<head>
    <title>상품 목록</title>
</head>
<body>
    <h1>상품 목록</h1>
    <ul>
        <th:block th:each="product : ${products}">
            <li th:text="${product.name} + ' - ' + ${product.price} + '원'"></li>
        </th:block>
    </ul>
</body>
</html>

✔️MVC 패턴 적용 후 개선된 점

비교 기존 (MVC 적용 전) MVC 패턴 적용 후
코드 구조 한 파일에서 모든 로직 처리 Model, View, Controller 분리
유지보수 UI 수정 시 코드 전체 수정 필요 UI만 따로 수정 가능
확장성 API 추가 어려움 API 추가, UI 변경 가능
재사용성 코드 중복 많음 Model, Repository 재사용 가능

📌 결론: Spring MVC 패턴이 필요한 이유

  1. 역할 분리 (Separation of Concerns)
    → UI(View), 데이터 처리(Model), 요청 처리(Controller)를 나눠서 유지보수를 쉽게 함.
  2. 재사용성과 확장성 증가
    → Model과 Controller는 그대로 두고 다른 View(React, 모바일 앱 등)로 확장 가능.
  3. 유지보수 용이
    → 특정 기능 수정 시 다른 부분에 영향을 주지 않음.
  4. 테스트 용이
    → Controller, Model을 따로 테스트 가능하여 품질 향상.