느리더라도 꾸준하게

안녕하세요? 제이온입니다.

 

오늘은 서블릿과 JSP의 차이점과 각각의 한계점을 극복하기 위해 뷰-컨트롤러 방식으로 구현한 구조를 소개하겠습니다.

 

 

서블릿과 JSP

사실 궁극적인 기능의 차이는 없습니다. 서블릿과 JSP 모두 Java를 이용하여 웹 페이지를 동적으로 생성하는 기능을 하기 때문이죠. 다만 역할의 차이가 있습니다. 이것은 글로 설명하기보다는 예시를 하나 들겠습니다.

 

회원 가입을 하고, 그 회원을 저장하고 조회하는 아주 작은 프로그램이 있다고 하겠습니다. 회원 가입 자체는 정적인 페이지가 대체하여도 무방하므로 회원 가입이후 생성된 유저의 정보를 보여주는 페이지를 만든다고 가정하겠습니다. 그렇다면, 서블릿으로 가입한 유저의 정보를 보여주는 코드를 아래처럼 작성할 수 있습니다.

 

 

@WebServlet(name = "memberSaveServlet", urlPatterns = "/servlet/members/save")
public class MemberSaveServlet extends HttpServlet {

    private final MemberRepository memberRepository = MemberRepository.getInstance();

    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        final String username = request.getParameter("username");
        final int age = Integer.parseInt(request.getParameter("age"));
        final Member member = new Member(username, age);
        memberRepository.save(member);

        response.setContentType("text/html");
        response.setCharacterEncoding("utf-8");
        final PrintWriter printWriter = response.getWriter();
        printWriter.write("<html>\n" +
            "<head>\n" +
            " <meta charset=\"UTF-8\">\n" +
            "</head>\n" +
            "<body>\n" +
            "성공\n" +
            "<ul>\n" +
            " <li>id=" + member.getId() + "</li>\n" +
            " <li>username=" + member.getUsername() + "</li>\n" +
            " <li>age=" + member.getAge() + "</li>\n" +
            "</ul>\n" +
            "<a href=\"/index.html\">메인</a>\n" +
            "</body>\n" +
            "</html>");
    }
}

 

 

HttpServletRequest를 이용하여 사용자가 입력한 값을 바탕으로 멤버 객체를 생성하고, 그 객체를 DB에 저장해 줄 수 있습니다. 그리고 정적인 HTML 코드에 동적으로 생성한 멤버의 정보를 중간에 껴넣음으로써 동적인 웹 페이지를 제공할 수 있게 됩니다. 문제는 자바 코드 안에 HTML 코드를 일일이 기입해야한다는 것입니다. 오타가 발생할 가능성이 높고, 유지 보수하기도 정말 지옥일 것입니다.

 

 

이를 보완하기 위해 나온 기술이 바로 JSP입니다. JSP는 자바 코드 안에 HTML 코드를 작성하는 것이 아니라 HTML 안에 자바 코드를 껴 넣는 방식으로 동적인 웹 페이지를 제공할 수 있습니다.

 

 

<%@ page import="hello.servlet.basic.domain.member.Member" %>
<%@ page import="hello.servlet.basic.domain.member.MemberRepository" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%
    final MemberRepository memberRepository = MemberRepository.getInstance();
    final String username = request.getParameter("username");
    final int age = Integer.parseInt(request.getParameter("age"));
    final Member member = new Member(username, age);
    memberRepository.save(member);
%>
<html>
<head>
    <title>Title</title>
</head>
<body>
성공
<ul>
    <li>id=<%=member.getId()%>
    </li>
    <li>username=<%=member.getUsername()%>
    </li>
    <li>age=<%=member.getAge()%>
    </li>
</ul>
<a href="/index.html">메인</a>
</body>
</html>

 

 

문법은 모르셔도 됩니다. 상단부에는 비즈니스 로직이 들어있고, 하단부에는 HTML 코드가 있고 중간에 '<% ~ %>' 문법을 이용하여 자바 코드를 껴 넣는 것을 알 수 있습니다. 확실히 개발자가 일일이 write()로 HTML 코드를 작성하는 것보다 훨씬 나아 보입니다. 다만, JSP 코드를 보면 Java 코드, 데이터를 조회하는 리포지토리 등등 다양한 코드가 모두 JSP에 노출되어 있기때문에 유지 보수하기에는 서블릿보다는 낫지만 그래도 아주 힘들 것입니다.

 

 

서블릿과 JSP을 보완한 MVC 패턴의 등장

서블릿과 JSP는 모두 뷰와 비즈니스 로직을 한 곳에서 처리한다는 한계가 있었습니다. 자, 이제 제가 포스팅 초반부에 이야기했던 서블릿과 JSP의 역할 차이를 설명드리겠습니다.

 

서블릿 코드를 보면 HTML 코드를 넣는다는 부분만 불편하지, 데이터를 읽고 가져와서 DB와 통신하고 비즈니스 로직을 호출하는 부분은 편리합니다. 그래서 서블릿은 Controller 역할을 맡기 적합합니다.

 

JSP 코드를 보면 서블릿에서 편리한 데이터 처리, DB 통신, 비즈니스 호출 부분이 불편하지만, HTML 코드 안에 Java 코드를 껴넣는 것이므로 View 역할을 맡기 적합합니다.

 

즉, 각자의 특화된 분야가 있으므로 둘을 합치고 각자의 업무를 분담하면 훨씬 효율적인 프로그램이 될 것입니다.

 

 

MVC 패턴이란?

MVC 패턴은 하나의 서블릿이나 JSP로 처리하던 것을 컨트롤러와 뷰, 모델 영역으로 역할을 나눈 것을 말합니다.

 

컨트롤러는 HTTP 요청을 받아서 파라미터를 검증하고, 비즈니스 로직을 실행합니다. 그리고 뷰에 전달할 결과 데이터를 조회해서 모델에 담습니다.

 

모델은 뷰에 출력할 데이터를 담아둡니다.

 

는 모델에 담겨있는 데이터를 사용해서 화면에 그리는 일을 하는데, HTML을 생성하는 부분을 생각하시면 되겠습니다.

 

 

 

 

그림으로 정리하면 위 구조와 같습니다. 서비스와 리포지토리 계층이 따로 분리되어 있는데 이것은 컨트롤러에서 비즈니스 로직이 한꺼번에 들어가면 유지 보수가 불편해서 한 번 더 나눈 것입니다.

 

 

한 번 코드로 MVC 패턴을 적용해 보겠습니다.

 

 

// Controller
@WebServlet(name = "mvcMemberSaveServlet", urlPatterns = "/servlet-mvc/members/save")
public class MvcMemberSaveServlet extends HttpServlet {

    private final MemberRepository memberRepository = MemberRepository.getInstance();

    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        final String username = request.getParameter("username");
        final int age = Integer.parseInt(request.getParameter("age"));
        final Member member = new Member(username, age);
        memberRepository.save(member);

        request.setAttribute("member", member);
        final String viewPath = "/WEB-INF/views/save-result.jsp";
        final RequestDispatcher dispatcher = request.getRequestDispatcher(viewPath);
        dispatcher.forward(request, response);
    }
}

// View
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
성공
<ul>
    <li>id=${member.id}
    </li>
    <li>username=${member.username}
    </li>
    <li>age=${member.age}
    </li>
</ul>
<a href="/index.html">메인</a>
</body>
</html>

 

 

서블릿에서 비즈니스 로직을 수행하고 뷰에 그릴 객체를 담아서 뷰에 보냅니다. 뷰로 이동하는 코드는 dispatcher.forward()를 사용합니다. 그러면 JSP는 서블릿에 있는 데이터를 가져와서 출력만 합니다.

 

각자 특화된 기능을 분담함으로써 유지 보수 측면에서 훨씬 보기 좋은 코드가 된 것을 알 수 있습니다.

 

 

정리

이번 포스팅에서는 동적 웹 페이지를 만드는 서블릿과 JSP를 구현한 코드, 그 두 가지 차이점, 마지막으로 둘을 합친 MVC 패턴까지 알아 보았습니다. 이정도로만 해도 깔끔한 코드처럼 보이지만, 서블릿에서 매번 dispatcher를 정의하고 호출해야 한다는 단점이 있습니다. 다음 시간에는 이 단점을 해결해 보겠습니다.

 

 

출처

 

[Web] Servlet과 JSP의 차이와 관계 - Heee's Development Blog

Step by step goes a long way.

gmlwjd9405.github.io

 

 

 

스프링 핵심 원리 - 기본편 - 인프런 | 강의

스프링 입문자가 예제를 만들어가면서 스프링의 핵심 원리를 이해하고, 스프링 기본기를 확실히 다질 수 있습니다., 스프링 핵심 원리를 이해하고, 성장하는 개발자가 되어보세요! 📣 확인해주

www.inflearn.com

 

donaricano-btn

이 글을 공유합시다

facebook twitter kakaoTalk kakaostory naver band

본문과 관련 있는 내용으로 댓글을 남겨주시면 감사하겠습니다.

비밀글모드

  1. 포스팅 잘 보고 갑니다 ^^
    2021.06.20 13:04 신고
  2. 코딩왕
    우왕!
    2021.07.01 14:36
  3. 우왕
    진촤 이해 잘가는 글 입니다 !
    2021.07.19 10:44