MVC, Spring MVC

star_pooh·2024년 12월 5일
0

TIL

목록 보기
30/39
post-thumbnail

MVC

Template Engine

동적인 웹 페이지를 생성하기 위해 사용되는 도구이며, 템플릿을 기반으로 정적인 부분과 동적인 데이터를 결합하여 HTML, XML 등의 문서를 생성하는 역할을 수행. SSR(Server Side Rendering)에 사용.

  • 템플릿 엔진이 나온 이유
    • 자바 코드로 HTML을 만드는 것이 아닌 HTML 문서에 동적으로 변경해야 하는 부분만 자바 코드를 넣을 수 있다면 더 편리하기 때문에
  • 대표적인 템플릿 엔진
    • Thymeleaf
      • Spring과 통합이 잘 되어 있으며 다양한 기능 포함
    • JSP(Java Server Pages)
      • 예전엔 많이 사용했으나 현재는 잘 쓰지 않는 추세

MVC 패턴 개요

Servlet이나 JSP만으로 비즈니스 로직과 View Rendering까지 모두 처리하면 너무 많은 역할(= 책임이 너무 많음)을 하게 되고 유지보수가 굉장히 어려워져서 고안된 패턴. Web Application은 일반적으로 MVC(Model View Controller) 패턴을 사용.

  • Servlet과 JSP 구조

  • Servlet 문제점
    • 화면을 그리는 View 영역과 비즈니스 로직이 모두 섞여있음

  • Servlet 동작 순서
    1. 사용자가 Client(브라우저)를 통해 서버에 HTTP Request(API 요청)을 함
      2. 요청을 받은 Servlet 컨테이너는 HttpServletRequest, HttpServletResponse 객체를 생성
      3. 설정된 정보(URL, HTTP Method)를 통해 어떠한 Servlet에 대한 요청인지 조회
      4. 해당 Servlet에서 service 메서드를 호출한 뒤 브라우저의 요청 Method에 따라 doGet() 혹은doPost() 등의 메서드를 호출
      5. 서버에서 HttpServletResponse 객체에 응답을 담아 Client(브라우저)에 반환
      6. 응답이 완료되면 생성한 HttpServletRequest, HttpServletResponse 객체를 소멸
  • JSP 문제점
    • Servlet 코드에서 HTML을 만드는 부분인 View가 분리되었지만, 비즈니스 로직의 일부가 JSP 파일 안에 존재
    • 여전히 많은 책임을 가지고 있으며 유지 보수가 어려움

MVC 패턴

하나의 Servlet이나 JSP로 처리하던 것들을 Model, View, Controller 영역으로 나눈 것.

  • 핵심 내용
    • 서로 연관이 없는 코드끼리 함께 존재할 필요가 없기 때문에 완전히 분리
      • 화면 구성에 수정이 발생하면 View 변경
      • 요구사항에 수정이 발생하면 비즈니스 로직 변경
  • MVC 패턴 구조

  • Controller
    • HTTP Request를 전달받아 파라미터를 검증
    • 비즈니스 로직 실행
      • 비즈니스 로직을 컨트롤러에 포함하게되면 많은 역할을 담당하게 되므로 Service Layer를 별도로 만들어서 처리
      • Database와 상호작용 하는 Repository Layer를 추가로 구성
      • 컨트롤러도 비지니스 로직을 포함할 수 있지만 일반적으로 Service Layer를 호출
    • View에 전달할 결과를 조회하여 Model 객체에 임시로 저장
  • Model
    • View에 출력할 Data를 저장하는 객체
    • View는 비즈니스 로직이나 Data 접근을 몰라도 되며, View Rendering에만 집중(책임 분리)
  • View
    • Model 객체에 담겨져 있는 Data를 사용하여 화면을 Rendering

MVC 패턴의 문제점

MVC 패턴 적용 후 View는 화면을 그리는 역할만 수행하면 되었지만 Controller는 여전히 문제가 존재.

  • View로 이동하는 forward(Servlet에서 다른 Servlet이나 JSP 호출)가 중복 호출됨
  • View의 path 입력이 중복됨
    • JSP 파일의 경로 혹은 이름이 바뀌면 모두 변경되어야 함
    • JSP 이외의 확장자를 사용하면 전체가 변경되어야 함
  • JSP에서 모두 해결하기 때문에 HttpServletResponse 객체를 사용하는 경우가 적음
    • HttpServletRequestHttpServletResponse는 테스트 코드를 작성하기도 힘듦
  • 공통 기능이 추가될수록 컨트롤러에서 처리해야 하는 부분이 증가

프론트 컨트롤러 패턴

Servlet(Controller)이 호출되기 전에 공통 기능을 하나의 Servlet에서 처리해주는 패턴. 프론트 컨트롤러(Servlet) 하나에 모든 클라이언트측 요청이 들어옴.

  • 모든 요청을 하나의 프론트 컨트롤러가 받으며 공통 기능을 처리
  • 요청을 처리할 수 있는 컨트롤러를 찾아서 호출 (Controller Mapping)
  • 프론트 컨트롤러를 제외한 나머지 컨트롤러는 Servlet을 사용하지 않아도 됨
    • 일반 컨트롤러들은 HttpServlet을 상속받거나, @WebServlet을 사용하지 않아도 됨

프론트 컨트롤러의 문제점

  • 공통 처리 로직에 모든 컨트롤러가 연결되기 위해서는 모든 컨트롤러의 리턴 형태가 동일해야 함
  • 하지만, 컨트롤러마다 리턴 형태는 다를 수 있으며 이것을 동일하게 맞추려고 한다면, 해당 애플리케이션은 확장성, 유지보수성을 잃게 됨
  • 공통 로직에서 리턴 형태별로 처리할 수 있지만 그렇게 되면 책임이 너무 커짐
  • 또한, 컨트롤러에서 리턴 형태가 변경되면 공통 로직도 변경되어야 함

어댑터 패턴

다양한 컨트롤러(Handler)를 유연하게 만들기위해 도입된 패턴. 컨트롤러들은 동일한 인터페이스를 구현하도록 하고 해당 인터페이스와 공통 로직 사이에 어댑터를 두어 유연하게 만드는 방식.

  • 어댑터 패턴 구조
    • 컨트롤러(Handler)는 비지니스 로직을 처리하고 알맞은 결과를 반환
    • 어댑터는 공통 로직과 컨트롤러(Handler)를 연결
    • 프론트 컨트롤러는 공통으로 처리되는 로직을 수행
  • 어댑터 패턴 장점
    • 프론트 컨트롤러, 어댑터, 핸들러 모두 각자의 역할만 수행(책임 분리)
      - 새로운 컨트롤러(Handler)가 추가되어도 공통 로직의 변경이 발생하지 않음

Spring MVC

Spring MVC 구조

MVC 패턴에 프론트 컨트롤러 패턴, 어댑터 패턴이 적용된 구조.

  • 실행순서
    1. Client로 부터 HTTP 요청(Request)을 받음
    2. Handler 조회
    - Handler Mapping을 통해 요청 URL에 Mapping된 Handler(Controller)를 조회
    3. Handler를 처리할 Handler Adapter 조회
    4. Handler Adapter 실행(handle)
    - 알맞은 어댑터가 존재한다면 Handler Adapter에게 요청을 위임
    5. Handler 실행(호출)
    - Handler Adapter가 실제 Handler(Controller)를 호출하여 실행 및 결과 반환
    6. Model And View 반환(return)
    - Handler Adapter는 Handler가 반환 하는 정보를 ModelAndView 객체로 변환하여 반환
    7. viewResolver 호출(알맞은 View 요청)
    - View Resolver를 찾고 실행
    8. View 반환
    - View Resolver는 View의 논리 이름을 물리 이름으로 전환하는 역할을 수행하고 Rendering 역할을 담당하는 View 객체를 반환
    9. View Rendering
    - View를 통해서 View를 Rendering

    💡 DispatcherServlet

    • 클라이언트 HTTP Request를 알맞게 파싱하고 클라이언트에게 알맞은 응답을 반환
    • 핸들러 목록 정보와 핸들러 어댑터 목록 정보를 알고 있음

    💡 HandlerAdapter

    • 자신이 처리할 수 있는 Handler인지 확인할 수 있는 기능(Method)이 필요
    • 프론트 컨트롤러에서 요청을 위임받았을 때 핸들러에게 요청을 지시하는 기능이 필요
    • return 시 Handler로부터 전달받은 결과를 알맞은 응답으로 변환

    💡 Handler

    • 요청에 대한 로직을 수행하는 기능이 필요

0개의 댓글

관련 채용 정보