본문 바로가기
Spring/MVC 1

3. 서블릿, JSP, MVC 패턴

by wch_t 2024. 3. 13.

[기본 View]

Form : 회원 등록 폼
Save : Repository에 회원을 저장 및 저장 결과 확인
List : 모든 회원 조회

 

 

 

1. 서블릿만으로, 동적 HTML 만들기

 

MemberSaveServlet

 

문제점

- 자바 코드에 HTML 코드를 만들고 있어, 매우 복잡하고 비효율적이다.

 

해결책   

- HTML 문서에 동적으로 변경해야 하는 부분만, 자바 코드를 넣을 수 있게 한다.

*템플릿 엔진 : HTML 문서에 필요한 곳만 코드를 적용해서 동적으로 변경할 수 있다. (JSP, Thymeleaf, Freemarker, Velocity...)

 

 

 

 

 

2. JSP 사용한, 동적 HTML 만들기

build.gradle에 JSP 라이브러리 추가
save.jsp

- JSP는 서버 내부에서 서블릿으로 변환되어, 실행된다.

 

<%@ page contentType="text/html;charset=UTF-8" language="java" %>

: 'JSP 문서' 라는 뜻이다.

 

<% ~ %>

: 이 부분에는 자바 코드를 입력할 수 있다.

 

<%= ~ %>

: 이 부분에는 자바 코드를 출력할 수 있다.

 

 

문제점

서블릿으로 개발할 때는, View 화면을 위한 HTML 작업이 자바 코드에 섞여서 복잡했다.

JSP를 사용한 덕분에 뷰를 생성하는 HTML 작업을 깔끔하고 가져가고, 동적으로 변경이 필요한 부분에만 자바 코드를 적용했다.

그러나 여전히 문제가 남아있다.

회원을 저장하기 위한 비즈니스 로직, 결과를 HTML로 보여주기 위한 뷰 로직이 공존한다.

 

 

해결책

비즈니스 로직은 서블릿처럼 다른 곳(Controller)에서 처리하고, JSP는 목적에 맞게 HTML, View에 집중하도록 한다.

 

 

 

 

 

3. MVC 패턴 개요

 

배경

- 하나의 서블릿이나 JSP만으로 비즈니스 로직과 뷰 렌더링까지 모두 처리하게 되면,

   너무 많은 역할을 하게되고, 결과적으로 유지보수가 어려워진다.

 

- 두 부분은 변경 라이프 사이클이 다르다.

   이는 UI 수정, 비즈니스 로직 수정이 각각 다르게 발생할 가능성이 매우 높고, 대부분 서로에게 영향을 주지 않는다.

 

 

 

MVC 패턴

- 지금까지 학습한 것처럼, 하나의 서블릿이나 JSP로 처리하던 것을 Controller, View라는 영역으로 나눈 것을 말한다.

 

Controller

- HTTP 요청을 받아서 파라미터를 검증하고, 비즈니스 로직(service)을 실행한다.

   그리고 뷰에 전달할 데이터가 있다면 조회해서 모델(repository)에 담는다. 

 

cf. 일반적으로 비즈니스 로직은 Service라는 계층을 별도로 만들어서 처리한다.

그리고, Controller는 비즈니스 로직이 있는 서비스를 호출하는 역할을 담당한다.

 

 

~ JPA 강의

GetMapping.

     : Repository에서 List<Order> 조회하는 로직

@GetMapping("/api/v3/simple-orders")
public List<SimpleOrderDto> ordersV3() {
    // entity를 조회해서, entity를 DTO로 변환하는 방식
    List<Order> orders = orderRepository.findAllWithMemberDelivery();

    List<SimpleOrderDto> result = orders.stream()
            .map(o -> new SimpleOrderDto(o))
            .collect(Collectors.toList());

    return result;
}

 

PostMapping.

     : Service 비즈니스 로직 실행

@PostMapping("/api/v2/members")
public CreateMemberResponse saveMemberV2(@RequestBody @Valid CreateMemberRequest request) {
    //System.out.println("name = 1" + request.getUsername());

    Member member = new Member();
    member.setUsername(request.getUsername());

    Long id = memberService.join(member);
    return new CreateMemberResponse(id);
}

 

 

 

Model

- 뷰에 출력할 데이터를 담아둔다. 뷰가 필요한 데이터를 모두 모델에 담아서 전달해주는 덕분에,

   뷰는 비즈니스 로직이나 데이터 접근을 몰라도 되고, 화면을 렌더링하는 일에 집중할 수 있다.

 

- 위의 설명은 이론에 해당한다. 실무에서는 domain을 정의하여 각 객체의 정보를 담는다.

  (실제로 모든 domain을 하나의 model에 정의하면 유지보수 하기 매우 힘들어질 것이다..)

 

 

 

View

- 모델에 담겨있는 데이터를 사용해, 화면을 그리는 일에 집중한다.

 

- SSR(서버 사이드 렌더링)에서는 jsp / thymeleaf .. 를 사용해서 View를 그리는 코드를 작성한다.

  보통 CSR(클라이언트 사이드 렌더링)로 클라이언트에게 return API(json) 로 응답하면 된다.

 

MVC 패턴1 (Service X)
MVC 패턴2 (Service O)

 

 

 

 

 

4. MVC 패턴 적용

 

서블릿Controller로 사용하고, JSPView로 사용해서 MVC 패턴을 적용한다.

ModelHttpServletRequest 객체를 사용한다.

request는 내부에 데이터 저장소를 가지고 있는데, setAttribute() / getAttribute()를 사용해 데이터를 보관 및 조회할 수 있다.

 

MvcMemberListServlet
members.jsp

 

dispatcher.forward() : 다른 서블릿이나 JSP로 이동할 수 있는 기능으로, 서버 내부에서 다시 호출이 발생한다.

 

/WEB-INF : 이 경로안에 JSP가 있으면 외부에서 직접 JSP를 호출할 수 없다. (Controller에서만 호출 가능)

- 프로젝트 내의 JSP를 참조할 때, /WEB-INF/views/  폴더를 사용해야 한다.

 

cf. Thymeleaf나 Freemarke 는 SpringResourceTemplateResolver를 사용하므로,

      classpath 내의 템플릿만 자체 참조하여 WEB-INF가 필요없다!

 

 

 

 

 

5. MVC 패턴 한계

 

단점

 

1) forward() 중복

View로  이동하는 코드가 항상 중복 호출된다.

 

2) ViewPath 중복

/WEB-INF/views/---.jsp 가 반복된다.

템플릿 엔진의 변경이 있을 경우, 전체 코드를 변경해야 한다.

 

3) 사용하지 않는 코드

HttpServletResponse response는 현재 코드에서 사용되지 않는다.

 

 

 

문제점

- 정리하면, 공통 처리가 어렵다.

 

 

해결책

- 이 문제를 해결하기 위해, Controller 호출 전에 먼저 공통 기능을 처리해야 한다.

   다음 방법으로는 '수문장' 역할을 하는 Front Cotroller 패턴을 도입하여 해결하도록 한다.

'Spring > MVC 1' 카테고리의 다른 글

6. 스프링 MVC - 기본 기능  (0) 2024.03.18
5. 스프링 MVC - 구조 이해  (0) 2024.03.16
4. MVC 프레임워크 만들기  (0) 2024.03.14
2. 서블릿  (0) 2024.03.11
1. 웹 애플리케이션 이해  (0) 2024.03.10