Template Engine
📌 동적인 웹 페이지를 생성하기 위해 사용되는 도구이며 템플릿을 기반으로 정적인 부분과 동적인 데이터를 결합하여 HTML, XML 등 의 문서를 생성하는 역할을 수행한다.
- 우리가 흔히 말하는 UI(User Interface)를 만들며, SSR(Server Side Rendering)에 사용된다.
- 정적 출력은 [안내 메시지]와 같은 모든 사용자에게 동일하게 보이는 데이터를 말하고 동적 데이터는 [사용자 이름]과 같은 사용자, 상황마다 다른 결과를 표현하는 데이터다.
- 아래와 같이 서버에서 보내는 데이터를 html쪽에서 정의하는 방식으로 접근이 편리하게 만들어준다.
<!-- 정적 출력 -->
<h1>안녕하세요, 방문해주셔서 감사합니다!</h1>
<!-- 동적 출력 -->
<p>안녕하세요, <span th:text="${name}">이름</span>님!</p>
[실제 출력]
<!-- 정적 출력 -->
<h1>안녕하세요, 방문해주셔서 감사합니다!</h1>
<!-- 동적 출력 -->
<p>안녕하세요, <span>철수</span>님!</p>
- 템플릿 엔진이 나온 이유
- 자바 코드로 HTML을 만들어 내는 것이 아닌 HTML 문서에 동적으로 변경해야 하는 부분만 자바 코드를 넣을 수 있다면 더 편리하다.
- 대표적인 템플릿 엔진
- Thymeleaf
- Spring과 통합이 잘 되어있다.
- 다양한 기능을 포함하고 있다.
- JSP(Java Server Pages)
- 예전엔 많이 사용했으나, 현재 안 쓰는 추세
- FreeMarker
- Velocity
- Mustache
- Thymeleaf
MVC 패턴 개요
📌 Servlet이나 JSP만으로 비지니스 로직과 View Rendering 까지 모두 처리하면 너무 많은 역할을 하게 되고 유지보수가 굉장히 어려워져서(책임이 너무 많음) 고안된 패턴이다. Web Application은 일반적으로 MVC(Model View Controller) 패턴을 사용한다.
- Servlet 문제점
- 화면을 그리는 View 영역과 비지니스 로직이 Servlet 하나에 모두 섞여있다.
- 책임을 너무 많이 가지고 있다.
- 사용자가 Client(브라우저)를 통해 서버에 HTTP Request 즉, API 요청을 한다.
- 요청을 받은 Servlet 컨테이너는 HttpServletRequest, HttpServletResponse객체를 생성한다.
- 설정된 정보(URL, HTTP Method)를 통해 어떠한 Servlet에 대한 요청인지 찾는다.
- 해당 Servlet에서 service 메서드를 호출한 뒤 브라우저의 요청 Method에 따라 doGet() 혹은doPost() 등의 메서드를 호출한다.
- 서버에서 응답을 생성한 뒤 HttpServletResponse객체에 응답을 담아 Client(브라우저)에 반환한다.
- 응답이 완료되면 생성한 HttpServletRequest, HttpServletResponse객체를 소멸한다.
- JSP
- Servlet 코드에서 HTML을 만드는 부분인 View가 분리되었다.
- 하지만 여전히 문제가 있는데, Servlet만 사용할 경우 View를 위한 코드와 비지니스 로직을 처리하는 코드가 Servlet에 모두 존재하며 유지보수가 어려워진다.
- JSP를 사용하여 View를 분리하였지만 비지니스 로직의 일부가 JSP파일안에 존재한다. 여전히 책임이 많아 유지보수가 어렵다.
MVC 패턴
📌 하나의 Servlet이나 JSP로 처리하던 것들을 Model, View, Controller 영역으로 나눈것이다.
- 핵심 내용
- View가 분리된 이유의 핵심은 변경이다.
- 기획이 변하지 않는 이상 비지니스 로직과 View의 수정 원인은 별개로 발생한다.
- 화면 구성에 수정이 발생하면 View만 변경
- 요구사항에 수정이 발생하는 경우 비지니스 로직 변경
- 즉, 서로 연관이 없는 코드끼리 함께 존재할 필요가 없다. 완전히 분리하자
MVC 패턴 구조
- Controller
- 예시 코드에서 Servlet에 해당하는 영역이다.
- HTTP Request를 전달받아 파라미터를 검증한다.
- 비지니스 로직을 실행한다.
- 비지니스 로직을 Controller에 포함하게되면 Controller가 너무 많은 역할을 담당하게 되어 일반적으로 Service Layer를 별도로 만들어서 처리한다.
- Database와 상호작용 하는 Layer를 따로 구분하여 Repository Layer를 추가로 구성한다.
- 위와 관련된 자세한 내용인 Layered Architecture는 다음 강의에서 알아보자.
- Controller도 비지니스 로직을 포함할 수 있지만 일반적으로 Service Layer를 호출하는 역할을 담당한다.
- View에 전달할 결과를 조회하여 Model 객체에 임시로 저장한다.
- Model
- View에 출력할 Data를 저장하는 객체이다.
- View는 비지니스 로직이나 Data 접근을 몰라도 되고 View Rendering에만 집중하면 된다.(책임 분리)
- View
- 예시 코드에서 JSP에 해당하는 영역이다.
- Model 객체에 담겨져 있는 Data를 사용하여 화면을 Rendering 한다.
MVC 패턴의 문제점
📌 MVC 패턴을 적용 후 View의 역할은 필요한 데이터를 Model 에서 참조하여 화면을 그리는 역할만 수행하면 된다. 하지만 Controller에 해당하는 부분은 여전히 문제를 가지고 있다.
- 문제점
- dispatcher.forward(request, response) View로 이동하는 forward( 서버가 하나의 요청을 다른 리소스(예: JSP, 서블릿)로 전달 )가 항상 중복 호출된다.
- String path= “/WEB-INF/views/new-form.jsp” View의 path를 입력(중복 작업)한다.
- jsp 파일의 경로 혹은 이름이 바뀌면 해당 코드가 변경되어야 한다.
- JSP 이외의 확장자를 사용하려면 전체가 변경되어야 한다.
- 위의 내용을 설명하면, 클라에서 서버에 계속해서 같은 내용을 반복 요청한다는 것, 그런데 그걸 받는 컨트롤러가 하나에만 배치되면 되는데 다 각각 배치된다는 것.. (카페 알바에게 아메리카노 3잔시켰는데 다른 주문도 많은데 알바 3명이서 1개씩 만들고 있다...)
- HttpServletResponse 객체를 사용하는 경우가 적다. (JSP에서 모두 해결하기 때문)
- HttpServletRequest와 HttpServletResponse는 Test 코드를 작성하기도 매우 힘들다.
- 공통 기능이 추가될수록 Controller에서 처리해야 하는 부분들이 많아진다.
- 공통 기능 처리
- 모든 컨트롤러에서 공통으로 적용되는 기능을 뜻한다.
- 공통 기능을 Method로 분리하여 각각의 컨트롤러에서 사용하면 되는것 아닌가요? 라고 생각이 가능하지만, 공통 기능으로 만들어놓은 Method 또한 항상 중복적으로 호출이 필요합니다. 또한, 사람인 개발자가 작업하다보면 Method를 호출하는 일을 깜빡 할수도 있고 Method가 많아지면 많아질수록 Controller의 책임이 점점 커진다. 이를 위해 아래의 대안이 나왔다.
프론트 컨트롤러 패턴
📌 Servlet(Controller)이 호출되기 전에 공통 기능을 하나의 Servlet에서 처리해주는 패턴이다. 프론트 컨트롤러(Servlet) 하나에 모든 클라이언트측 요청이 들어온다.
- 프론트 컨트롤러의 역할
- 모든 요청을 하나의 프론트 컨트롤러가 받는다.
- 공통 기능을 처리한다.
- 요청을 처리할 수 있는 Controller를 찾아서 호출한다.(Controller Mapping)
- 프론트 컨트롤러를 제외한 나머지 컨트롤러는 Servlet을 사용하지 않아도 된다.
- 일반 Controller들은 HttpServlet을 상속( HTTP 프로토콜 기반의 요청과 응답을 처리하기 위해 제공되는 클래스 )받거나, @WebServlet(URL 매핑 여기서는 url과 servlet과의 매핑을 말한다.)을 사용하지 않아도 된다. = 프론트 컨트롤러가 처리함
- @WebServlet의 설명이 이해가 안될 수도 있는데, url은 말 그대로 주소 식별자다. url에 보내는 요청을 보고 어느 servlet에서 처리를 할지 정하고 해당 servlet에 배치(매핑)하는 과정은 완전별개의 문제이다.
- 프론트 컨트롤러 의문점
- 프론트 컨트롤러를 사용하면 모든 컨트롤러에서 같은 형태의 응답을 해야하는가?
-
- 위 그림처럼 공통 처리 로직에 모든 컨트롤러가 연결되기 위해서는 모든 컨트롤러가 return 하는 결과의 형태가 동일해야 한다.
- 하지만, Controller 마다 로직이나 응답해야하는 결과는 당연히 다를테고 응답을 동일하게 맞추려고 한다면 해당 애플리케이션은 확장성, 유지보수성을 잃는다.
- 공통 로직에서 응답별로 퍼즐을 다시 하나하나 처리할 수 있으나 공통 부분의 책임이 너무 커지게된다. 또한, 컨트롤러에서 반환되는 결과가 달라지면 공통처리 부분의 변경또한 불가피하다.
- 그래서 아래의 대안이 또 나왔다.
어댑터 패턴
📌 어댑터 패턴은 호환되지 않는 인터페이스를 가진 클래스들이 함께 동작할 수 있도록 중간에서 변환을 도와주는 디자인 패턴입니다. 주로, 이미 존재하는 코드와 새로운 코드 사이의 호환성 문제를 해결하는 데 사용됩니다.
- 컨트롤러들은 동일한 인터페이스를 구현하도록 하고 해당 인터페이스와 공통 로직 사이에 어댑터를 두어 유연하게 만든다. 서로 다른 인터페이스를 갖는 두 클래스를 연결해주는 패턴이다.
- 이해가 잘 안된다면 아래의 접은글을 참고
더보기
비유: 요리사, 레시피, 그리고 주방
- 요리사(각 컨트롤러)
- 요리사는 특정 요리(기능)를 책임지고 있습니다.
- 하지만 요리사는 "자신만의 레시피(방법)"만 알고, 다른 요리사들이 어떤 레시피를 사용하는지 알지 못할 수도 있습니다.
- 레시피(인터페이스 또는 요청 처리)
- 레시피는 요리사가 따라야 하는 공통된 규칙(인터페이스)입니다.
- 예를 들어, 레시피에 따라 어떤 순서로 재료를 조합할지 정의됩니다.
- 모든 요리사가 이 레시피를 준수해야 주방이 동작을 관리하기 쉬워집니다.
- 주방(공통 로직 또는 프론트 컨트롤러)
- 주방은 요리사들이 만든 다양한 레시피를 필요한 시점에 호출하고, 손님(사용자)에게 제공할 음식을 최종적으로 내놓습니다.
- 주방은 모든 요리를 직접 만들지 않고, 요리사들에게 필요한 일을 분담시킵니다.
어댑터 패턴의 맥락에서
주방에서 레시피(인터페이스)를 공유하여 요리사들이 협업 가능하게 만드는 구조는 어댑터 패턴과 비슷합니다.
- 주방(공통 처리 로직)과 요리사(개별 로직)가 서로 다른 방식을 사용하고 있다면, 어댑터(중간 번역기)를 통해 조율할 수 있습니다.
프론트 컨트롤러를 요리사와 주방에 비유하면
- 요리사 (각 컨트롤러)
- @Controller를 사용한 일반 컨트롤러.
- HTTP 요청이 들어오면, 요리사(컨트롤러)는 특정 요리를 준비하는 역할을 수행.
- 클라이언트 요청에 따라 요리사는 자신의 비즈니스 로직에만 집중.
- 레시피 (인터페이스)
- 요리사가 동작할 때 따라야 하는 규칙.
- 예를 들어, Spring MVC에서는 @RequestMapping 또는 @GetMapping 등의 애너테이션이 이런 역할을 함.
- 주방 (프론트 컨트롤러)
- Spring의 DispatcherServlet 같은 역할.
- 모든 요청이 주방으로 들어오고, 주방은 적절한 요리사(컨트롤러)를 찾아 요청을 전달.
- 공통적인 작업(예: 인증, 로깅, 예외 처리 등)을 주방에서 처리한 뒤 요리사에게 넘김.
- 컨트롤러(Handler)는 비지니스 로직을 처리하고 알맞은 결과를 반환한다.
- 어댑터는 공통 로직과 컨트롤러(Handler)가 자연스럽게 연결되도록 한다.
- 프론트 컨트롤러는 공통으로 처리되는 로직을 수행한다.
- 어댑터 패턴 장점
- 프론트 컨트롤러, 어댑터, 핸들러 모두 각자의 역할만 수행한다. (책임 분리)
- 새로운 컨트롤러(Handler)가 추가되어도 컨트롤러와 어댑터만 추가한다면 공통 로직의 변경이 발생하지 않는다.
요약
- Servlet 사용
- 비지니스 로직을 처리하는 코드와 화면을 그리는 View 코드가 함께 존재하는 문제
- JSP 사용
- View 에 해당하는 코드를 분리하였지만, 여전히 비지니스 로직을 JSP에 포함하는 문제
- MVC 패턴 사용
- 공통 로직을 처리하는것에 코드가 중복되는 문제
- 프론트 컨트롤러 패턴 사용
- 공통 로직을 하나의 입구에서 처리하기 위해서 프론트 컨트롤러 패턴 적용
- 각각의 핸들러 호출 후 응답을 프론트 컨트롤러에 맞게 변형시켜야 하는 문제
- Spring MVC 사용
- 프론트 컨트롤러 패턴, 어댑터 패턴이 모두 적용된 현재
- 우리가 사용하는 Spring을 이용한 Web Application 개발 방식에 사용됨
- Spring은 MVC 패턴에 프론트 컨트롤러 패턴, 어댑터 패턴이 적용되어 있다.
'CS ( Computer Science ) > 네트워크 (Networking)' 카테고리의 다른 글
[Net] Token & JWT (0) | 2024.12.29 |
---|---|
[Net] Cookie (1) | 2024.12.28 |
[Net] API 설계 (0) | 2024.12.12 |
[Net] Cookie / Session / Token / JWT / Filter (0) | 2024.12.12 |
[Net] 네트워크 기본 요약 (1) | 2024.12.06 |