온라인 강의/Spring Framework

[스프링 MVC 1편] 서블릿, JSP, MVC 패턴

코드몬스터 2024. 5. 11. 12:24
728x90

강의 요약

  • 웹 애플리케이션을 Servlet / 템플릿 / MVC 세 방법으로 개발해보자.
  • Servelt 개발 → 템플릿(JSP) 개발 → MVC 패턴 
  • Servlet은 자바 코드에 HTML이 있어 불편하다.
  • 템플릿은 HTML 문서에 서비스 로직 등이 있어 불편하다.
  • 그래서 등장한게 MVC 패턴으로 각 역할을 Model, View, Controller로 나눈다.

 

회원 관리 앱 애플리케이션 요구 사항

 

기능 요구사항

  • 회원 저장
  • 회원 목록 조회

 

회원( Member )도메인 모델

@Getter @Setter
public class Member {

    private Long id;
    private String username;
    private int age;

    public Member () {
    }

    public Member(String username, int age) {
        this.username = username;
        this.age = age;
    }
    
}

 

 

회원 저장소

package com.inflearn.hello.servlet.domain.member;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


/** 
 * 동시성 문제가 고려되어 있지 않음, 실무에서는 ConcurrentHashMap, AtomicLong 사용 고려
 * */
public class MemberRepository {

    private static Map<Long, Member> store = new HashMap<>();
    private static long sequence = 0L;

    // 싱글톤 패턴은 전체 시스템에서 하나의 인스턴스만 생성하도록 보장하고,
    // 이 인스턴스에 전역적으로 접근할 수 있도록 하는 디자인 패턴입니다.
    private static final MemberRepository instance = new MemberRepository();

    public MemberRepository() {
    }

    public static MemberRepository getInstance() {
        return instance;
    }

    public Member save(Member member) {
        member.setId(++sequence);
        store.put(member.getId(), member);
        return member;
    }

    public Member findById(Long id) {
        return store.get(id);
    }

    public List<Member> findAll() {
        return new ArrayList<>(store.values());
    }

    public void clearStore() {
        store.clear();
    }

}

 

 


서블릿으로 회원 관리 웹 애플리케이션 만들기

  • 서블릿과 자바코드만으로 HTML을 만들었다.
  • 서블릿으로 동적으로 원하는 HTML을 마음껏 만들 수 있는데 정적인 HTML 문서라면 회원의 저장 결과 또는 회원 목록같은 동적인 HTML은 불가능하다.
  • 자바 코드에 HTML을 넣는 것은 매우 불편하고 비효율적이다.(Fig 2)

Fig 1.  웹 애플리 케이션 기능

템플릿 엔진

  • HTML 문서에서 동적으로 변경해야 하는 부분만 자바코드를 넣을 수 있으면 편리할 수 있다.
  • 그래서 나온 것이 템플릿 엔진이다.
  • 템플릿 엔진으로 HTML 문서 내부에서 필요한 코드를 적용해서 동적으로 변경 가능하다.
  • JSP, Thymeleaf 등이 있다.

Fig 1. 자바 코드에 HTML을 넣는 것은 비효율적이다.

 

JSP 페이지 만들기

  • <%  %>: 자바 코드를 작성할 수 있다.

자바 코드에서 작성한 서비스 부분을 JSP 템플릿을 사용해서 HTML 문서에 작성할 수 있다.

  비지니스 부분과 뷰 렌더링 부분이 섞여 있다.

 

회원 저장 JSP

<%@ page import="hello.servlet.domain.member.Member" %>
<%@ page import="hello.servlet.domain.member.MemberRepository" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>

<%
    // request, response 사용 가능
    // jsp는 나중에 servlet으로 변환된다.

    MemberRepository memberRepository = MemberRepository.getInstance();

    System.out.println("MemberSaveServlet.service");
    String userName = request.getParameter("userName");
    int age = Integer.parseInt(request.getParameter("age"));

    Member member = new Member(userName, age);
    memberRepository.save(member);
%>
<html>
    <head>
        <title>Title</title>
    </head>
    <body>
        <li>id=<%=member.getId()%></li>
        <li>username=<%=member.getUsername()%></li>
        <li>age=<%=member.getAge()%></li>
        <a href="/index.html">메인</a>
    </body>
</html>

 

 

회원 목록 JSP

<%@ page import="java.util.List" %>
<%@ page import="hello.servlet.domain.member.Member" %>
<%@ page import="hello.servlet.domain.member.MemberRepository" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%
    MemberRepository memberRepository = MemberRepository.getInstance();
    List<Member> memberList = memberRepository.findAll();
%>
<html>
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>

    <body>
        <a href="/index.html">메인</a>
        <table>
            <thead>
            <th>id</th>
            <th>username</th>
            <th>age</th>
            </thead>
            <tbody>
            <%
                for (Member member : memberList) {
                    out.write(" <tr>");
                    out.write(" <td>" + member.getId() + "</td>");
                    out.write(" <td>" + member.getUsername() + "</td>");
                    out.write(" <td>" + member.getAge() + "</td>");
                    out.write(" </tr>");
                }
            %>
            </tbody>
        </table>
    </body>
</html>

 

서블릿과 JSP 한계

  • 서블릿으로 개발할 때는 뷰(View) 화면을 위한 HTML을 만드는 작업이 자바 코드에 섞여서 지저분하고 복잡하다.
  • JSP를 사용해서 HTML 작업을 깔끔하게 정리할 수 있지만, JAVA 코드부터 데이터 조회 등 여러 기능을 담당.

MVC 패턴

 

MVC 등장

  • 비즈니스 로직은 서블릿 처럼 다른 곳에서 처리하고, JSP는 목적에 맞게 HTML로 화면(View)을 그리는 일에 집중.

 

Model-View-Controller

  • 컨트롤러(Controller): HTTP 요청을 받아서 파라미터를 검증하고 비즈니스 로직을 실행한다. 그리고 뷰에 전달할 결과를 조회해서 모델에 담는다.
  • 모델(Model): 뷰에 출력할 데이터를 담아둔다. 뷰가 필요한 데이터를 모두 모델에 담아서 전달해주는 덕분에 뷰는 비즈니스 로직이나 데이터 접근을 몰라도 되고, 화면을 렌더링 하는 일에 집중할 수 있다.
  • 뷰(View): 모델에 담겨있는 데이터를 사용해서 화면을 그리는 일에 집중한다. 여기서는 HTML을 생성하는 부분을 말한다.

 

MVC 패턴 1탄

  • 컨트롤러에 비즈니스 로직을 넣을 수 있다.
  • 그러면, 컨트롤러가 많은 역할을 맡게 된다.

MVC 패턴 1탄

 

MVC 패턴 2탄

  • 비즈니스 로직은 서비스(Service)라는 계층을 별도로 만들어서 처리한다.

MVC 패턴 2탄

 


MVC 패턴 - 적용

 

WEB-INF

  •  WAS에서 내부적으로 WEB-INF 폴더 내부에 JSP 파일이 있으면 직접 호출할 수 없다.

 

redirect vs forward

  • 리다이렉트(redirect)는 실제 클라이언트(웹 브라우저)에 응답이 갔다가, 클라이언트가 redirect 경로로 다시 요청한다.
    • 따라서 클라이언트가 인지할 수 있고, URL 경로도 실제로 변경된다.
  • 포워드(forward)는 서버 내부에서 일어나는 호출이기 때문에 클라이언트가 전혀 인지하지 못한다.

 

절대경로 vs 상대경로

  • 절대경로: /save
    • http://localhost:8080/save
  • 상대경로: save
    • http://localhost:8080/{현재 경로}/save

MVC 패턴 - 한계

MVC 패턴을 적용한 덕분에 컨트롤러의 역할과 뷰를 렌더링하는 역할을 명확하게 구분할 수 있다.

 

한계

  • 포워드 중복
  • ViewPath 중복
  • 사용하지 않는 코드

문제

  • 공동 처리가 어렵다
    • 기능이 복잡해질수록 컨트롤러에서 공통으로 처리해야 하는 부분이 점점 더 많이 증가할 것이다.
    • 단순히 공통 기능을 메서드로 뽑으면 될 것 같지만, 해당 메서드를 항상 호출해야하고, 실수로 호출하지 않으면 문제가 된다.

결론

  • 수문장 역할을하는 프론트 컨트롤러(Front Controller)가필요하다.
    (입구를 하나로)
  • 필터(Filter)랑은 다르다..!!