자바 백엔드 웹 기술의 진화과정(1), 서블릿, jsp, MVC 패턴

2022. 6. 8. 17:28·Back-End/Spring MVC

Java 백엔드 웹 기술의 발전과정에 따라서 순차적으로 적용시켜 볼 예정

서블릿 → JSP → MVC패턴 → 프론트 컨트롤러 패턴 → 스프링MVC

서블릿 방식

  • 회원 등록 폼
@WebServlet(name= "memberFormServlet", urlPatterns = "/servlet/members/new-form")
public class MemberFormServlet extends HttpServlet {

    private MemberRepository memberRepository = MemberRepository.getInstance();

    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        response.setContentType("text/html");
        response.setCharacterEncoding("utf-8");

        //회원등록 Html 작성 부분
        PrintWriter w = response.getWriter();
        w.write("<!DOCTYPE html>\n" +
                "<html>\n" +
                "<head>\n" +
                " <meta charset=\"UTF-8\">\n" +
                " <title>Title</title>\n" +
                "</head>\n" +
                "<body>\n" +
                "<form action=\"/servlet/members/save\" method=\"post\">\n" +
                " username: <input type=\"text\" name=\"username\" />\n" +
                " age: <input type=\"text\" name=\"age\" />\n" +
                " <button type=\"submit\">전송</button>\n" +
                "</form>\n" +
                "</body>\n" +
                "</html>\n");
    }

}
  • 회원 등록 결과 저장 Servlet
@WebServlet(name = "memberSaveServlet", urlPatterns = "/servlet/members/save")
public class MemberSaveServlet extends HttpServlet {

    private MemberRepository memberRepository = MemberRepository.getInstance();

    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //회원등록한 정보를 저장하는 로직
        String username = request.getParameter("username");
        int age = Integer.parseInt(request.getParameter("age"));

        Member member = new Member(username, age);
        memberRepository.save(member);

                //저장이 된 결과를 html로 응답해주는 로직
        response.setContentType("text/html");
        response.setCharacterEncoding("utf-8");
        PrintWriter w= response.getWriter();
        w.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>");
    }
}
  • 저장된 모든 member들을 List로 보여주는 Html
@WebServlet(name = "memberListServlet", urlPatterns = "/servlet/members")
public class MemberListServlet extends HttpServlet {
    private MemberRepository memberRepository = MemberRepository.getInstance();

    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        List<Member> members = memberRepository.findALl(); //멤버 객체 생성

        response.setContentType("text/html");              //응답 설정
        response.setCharacterEncoding("utf-8");

        //저장된 member를 출력해주는 HTML부분
        PrintWriter w = response.getWriter();
        w.write("<html>");
        w.write("<head>");
        w.write(" <meta charset=\"UTF-8\">");
        w.write(" <title>Title</title>");
        w.write("</head>");
        w.write("<body>");
        w.write("<a href=\"/index.html\">메인</a>");
        w.write("<table>");
        w.write(" <thead>");
        w.write(" <th>id</th>");
        w.write(" <th>username</th>");
        w.write(" <th>age</th>");
        w.write(" </thead>");
        w.write(" <tbody>");

        //반복문을 통해서 저장된 member수만큼 출력
        for (Member member : members) {
            w.write(" <tr>");
            w.write(" <td>" + member.getId() + "</td>");
            w.write(" <td>" + member.getUsername() + "</td>");
            w.write(" <td>" + member.getAge() + "</td>");
            w.write(" </tr>");
        }
        w.write(" </tbody>");
        w.write("</table>");
        w.write("</body>");
        w.write("</html>");
    }
}

서블릿 방식의 문제점

  • java코드만으로 HTML을 만들어야 하므로 매우 복잡, 비효율적
    →
    템플릿 엔진의 등장한 이유
  • 템플릿 엔진이란? - HTML 문서에서 필요한 곳만 코드를 적용해서 동적으로 변경
  • 템플릿 엔진 : JSP, Thymeleaf, Freemarker, Velocity 등

JSP 방식

  • Java언어를 기반으로 하는 Server Side 스크립트 언어
  • HTML 코드에 Java언어를 넣어서 동적인 웹 페이지 생성
  • Java코드에 HTML을 작성하는 비효율적인 문제를 개선
  • <%@ page contentType="text/html;charset=UTF-8" language="java" %> : 첫 줄은 JSP문서라는 뜻이다. JSP 문서는 이렇게 시작해야 한다.
  • <%@ page import="hello.servlet.domain.member.MemberRepository" %> : 자바의 import
  • 자바 코드 삽입 : <% ~~ %>
  • 자바 코드 출력 : <%= ~~ %>

JSP 예제

  • 회원 등록 폼
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<!-- 상대경로 사용, [현재 URL이 속한 계층 경로 + /save] -->
<form action="save" method="post">
    username: <input type="text" name="username"/>
    age: <input type="text" name="age"/>
    <button type="submit">전송</button>
</form>
</body>
</html>
  • 회원 저장

  • 회원 목록 조회

JSP방식의 문제점

  • Java의 비즈니스 로직이 모두 JSP에 노출
  • JSP가 비즈니스 로직 + 뷰 역할을 모두 담당
    → 규모가 커지면 유지보수가 힘들다
  • 비즈니스 로직과 뷰를 따로 관리 하기위해 MVC패턴이 등장

MVC패턴

개요

  • 변경의 라이프 사이클이 다르다
    • 비즈니스 로직수정 / UI 수정 은 각각 다르게 발생할 가능성이 높고 서로에게 영향을 주지 않는다.
    • 변경의 라이프사이클이 다른 부분을 하나의 코드로 관리하는것은 유지보수에 좋지 않다.
  • 기능 특화 
    • JSP같은 뷰 템플릿은 화면 렌더링에 최적화 되어있기 때문에 화면 렌더링 역할만 하는것이 가장 효과적이다.

MVC 패턴의 등장

  • Model : View에 출력할 데이터를 담아두는 역할
  • View : Model에 담겨있는 데이터를 통해 화면에 렌더링 하는 역할
  • Controller : HTTP 요청 파라미터를 검증 / 비즈니스 로직 실행 / 결과데이터를 Model에 담기

MVC패턴 적용

  • Servlet을 Controller로 사용
  • JSP를 View로 사용
  • HttpServletRequest를 Model로 사용 → request.setAttribute(), request.getAttribute() 메서드를 이용

예제

  • 회원 등록 폼 요청
@WebServlet(name ="mvcMemberFormServlet", urlPatterns = "/servlet-mvc/members/new-form")
public class MvcMemberFormServlet extends HttpServlet {
    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //viewPath의 경로에 있는 jsp파일을 Dispatcher에 넘겨서 요청
        String viewPath = "/WEB-INF/views/new-form.jsp";
        RequestDispatcher dispatcher = request.getRequestDispatcher(viewPath);
        dispatcher.forward(request,response);
    }
}
  • /WEB-INF : 해당 경로에 존재하는 jsp 파일은 외부에서 접근할수 없고, dispatcher를 통해서만 접근이 가능하다.
  • dispatcher : 다른 Servlet이나 JSP로 이동하는 기능을 담당

💡 Redirect 와 forward의 차이점?

     redirect : 실제 클라이언트에 응답이 갔다가, 클라이언트가 redirect경로로 다시 요청 → url경로 변경 O
     forward : 서버 내부에서 일어나는 호출 → url 경로 변경 X

 

  • 회원 정보 저장 로직
@WebServlet(name = "mvcMemberSaveServlet", urlPatterns = "/servlet-mvc/members/save")
public class MvcMemberSaveServlet extends HttpServlet {

    private MemberRepository memberRepository = MemberRepository.getInstance();

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

        Member member = new Member(username, age);
        memberRepository.save(member);

        //Model에 데이터를 보관
        request.setAttribute("member", member);

        //view로 데이터 전달
        String viewPath="/WEB-INF/views/save-result.jsp";
        RequestDispatcher dispatcher = request.getRequestDispatcher(viewPath);
        dispatcher.forward(request, response);
    }
}
  • 회원 리스트 조회
@WebServlet(name = "mvcMemberListServlet", urlPatterns = "/servlet-mvc/members")
public class MvcMemberListServlet extends HttpServlet {
    private MemberRepository memberRepository = MemberRepository.getInstance();

    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        List<Member> members = memberRepository.findALl();
        request.setAttribute("members", members);

        String viewPath = "/WEB-INF/views/members.jsp";
        RequestDispatcher dispatcher = request.getRequestDispatcher(viewPath);
        dispatcher.forward(request, response);
    }
}

MVC패턴의 문제점

  • forward 부분의 중복 : view로 이동하는 코드가 중복 호출된다.
RequestDispatcher dispatcher = request.getRequestDispatcher(viewPath);
dispatcher.forward(request, response);
  • viewPath 중복 : 모든 절대경로를 입력해야 하기 때문에 중복이 발생
String viewPath = "/WEB-INF/views/new-form.jsp";
  • 사용하지 않는 코드 : HttpServletRequest / HttpServletResponse 객체를 사용하지 않아도 객체로 받는 경우가 있다.
  • 공통처리의 어려움 : 공통으로 중복되는 부분을 하나로 처리하지 못해서 중복되는 부분이 많이 발생

정리

  • 공통부분을 효율적으로 처리하는 프론트 컨트롤러 패턴의 등장
반응형
'Back-End/Spring MVC' 카테고리의 다른 글
  • 자바 백엔드 웹 기술의 진화과정(3) - 웹 프론트 컨트롤러 v4, v5
  • 자바 백엔드 웹 기술의 진화과정(2) - 웹 프론트 컨트롤러 v1, v2, v3
  • 서블릿의 사용, HttpServletRequest, HttpServletResponse
  • [Spring MVC] - 웹 애플리케이션의 이해(HTTP, WAS, Servlet, 멀티 쓰레드, CSR, SSR)
LightSource
LightSource
어제보단 발전한 오늘의 나를 위한 블로그
    반응형
  • LightSource
    LightSourceCoder
    LightSource
  • 전체
    오늘
    어제
    • 분류 전체보기 (152)
      • Git (4)
      • Language (6)
        • Java (6)
      • Back-End (63)
        • Spring Boot (4)
        • MyBatis (1)
        • Oracle (1)
        • PL SQL (3)
        • JPA (26)
        • Spring Data JPA (5)
        • Spring MVC (8)
        • Spring (12)
        • Spring Security (2)
        • Redis (1)
      • Front-End (38)
        • 아이오닉 (2)
        • JSP (7)
        • JavaScript (4)
        • React (16)
        • TypeScript (3)
        • Angular (6)
      • AWS (1)
      • CI & CD (1)
      • 개발지식 (13)
        • 네트워크 (9)
        • CS 지식 (4)
      • 데이터모델링 (2)
      • Tool (1)
      • 프로젝트 (5)
      • 독후감 (2)
      • 잡생각 (0)
      • 면접 준비 (1)
      • 알고리즘 (14)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    배요소열추가
    리액트
    배열요소삭제
    배열요소수정
    react
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.0
LightSource
자바 백엔드 웹 기술의 진화과정(1), 서블릿, jsp, MVC 패턴
상단으로

티스토리툴바