[Spring Boot][4] 3-1. 서블릿, JSP, MVC 패턴

sorzzzzy·2021년 9월 6일
0

Spring Boot - RoadMap 1

목록 보기
27/46
post-thumbnail

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

✔️ 회원 정보

  • 이름 : username
  • 나이 : age

✔️ 기능 요구사항
1️⃣ 회원 저장
2️⃣ 회원 목록 조회


✔️ 회원 도메인 모델 만들기

package hello.servlet.domain.member;
import lombok.Getter;
import lombok.Setter;
@Getter @Setter

public class Member {
    // 식별자 id
    private Long id;
    private String username;
    private int age;
    
    // 기본 생성자
    public Member() {
    }
    
    // 생성자
    public Member(String username, int age) {
        this.username = username;
        this.age = age;
    }
}

✔️ 회원 저장소 만들기

package hello.servlet.domain.member;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class MemberRepository {

    private static Map<Long, Member> store = new HashMap<>();
    // id 가 하나씩 증가
    private static long sequence = 0L;

    // 싱글톤으로 만들 예정
    private static final MemberRepository instance = new MemberRepository();

    public static MemberRepository getInstance() {
        return instance;
    }

    // 싱글톤을 사용할 땐 private로 생성자를 막아 아무나 생성하지 못하게 해야 함
    private MemberRepository() {
    }

    public Member save(Member member) {
        // 시퀀스 값 증가
        member.setId(++sequence);
        store.put(member.getId(), member);
        return member;
    }

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

    // List<> : java.util 사용
    public List<Member> findAll() {
        return new ArrayList<>(store.values());
    }

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

✔️ 회원 저장소 테스트코드 만들기

📌 command + shift + t 로 테스트코드 자동 생성 가능

package hello.servlet.domain.member;

import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;
import java.util.List;

import static org.assertj.core.api.Assertions.assertThat;

class MemberRepositoryTest {
    MemberRepository memberRepository = MemberRepository.getInstance();
    
    // 테스트가 끝날 때 마다 초기화
    @AfterEach
    void afterEach() {
        memberRepository.clearStore();
    }
    
    @Test
    void save() {
        //given
        Member member = new Member("hello", 20);

        //when
        Member savedMember = memberRepository.save(member);

        //then
        Member findMember = memberRepository.findById(savedMember.getId());
        assertThat(findMember).isEqualTo(savedMember);
    }

    @Test
    void findAll() {
        //given
        Member member1 = new Member("member1", 20);
        Member member2 = new Member("member2", 30);
        memberRepository.save(member1);
        memberRepository.save(member2);

        //when
        List<Member> result = memberRepository.findAll();

        //then
        assertThat(result.size()).isEqualTo(2);
        assertThat(result).contains(member1, member2);
    }
}

⬆️ 테스트 실행 결과 👍🏻



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

✔️ MemberFormServlet - 회원 등록 폼 생성

package hello.servlet.web.servlet;
 import hello.servlet.domain.member.MemberRepository;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;


@WebServlet(name = "memberFormServlet", urlPatterns = "/servlet/members/new-form")
    public class MemberFormServlet extends HttpServlet {
    // 싱글톤으로 만들었기 때문에 new 사용이 불가
    private MemberRepository memberRepository=MemberRepository.getInstance();
    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{
                  response.setContentType("text/html");
                  response.setCharacterEncoding("utf-8");
                  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");
          }
    }

✔️ MemberSaveServlet - 회원 저장

package hello.servlet.web.servlet;

import hello.servlet.domain.member.Member;
import hello.servlet.domain.member.MemberRepository;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

@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 {
        // 실행되는지 확인
        System.out.println("MemberSaveServlet.service");
        // request.getParameter : 쿼리 파라미터 확인
        String username = request.getParameter("username");
        // 문자형식을 숫자타입으로 변환
        int age = Integer.parseInt(request.getParameter("age"));

        // 멤버 객체 생성
        Member member = new Member(username, age);
        System.out.println("member = " + member);
        memberRepository.save(member);

        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>");
    }
}

MemberSaveServlet 은 다음 순서로 동작한다!
1️⃣ 파라미터를 조회해서 Member 객체를 만든다.
2️⃣ Member 객체를 MemberRepository를 통해서 저장한다.
3️⃣ Member 객체를 사용해서 결과 화면용 HTML을 동적으로 만들어서 응답한다.

⬆️ http://localhost:8080/servlet/members/new-form 로 실행한 결과👍🏻


✔️ MemberListServlet - 모든 회원 목록 조회

package hello.servlet.web.servlet;

import hello.servlet.domain.member.Member;
import hello.servlet.domain.member.MemberRepository;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.List;

@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 {

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

        List<Member> members = memberRepository.findAll();
        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>");
        /*
        w.write("    <tr>");
        w.write("
        w.write("
        w.write("
        w.write("    </tr>");
        */

        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>");
    }
}

MemberListServlet 은 다음 순서로 동작한다!
1️⃣ memberRepository.findAll() 을 통해 모든 회원을 조회한다.
2️⃣ 회원 목록 HTML을 for 루프를 통해서 회원 수 만큼 동적으로 생성하고 응답한다.

⬆️ http://localhost:8080/servlet/members 로 실행한 결과👍🏻

템플릿 엔진으로...🌟
지금까지 서블릿과 자바 코드만을 이용했는데 정적인 것이 아닌 동적인 HTML을 만드는 일은 불가능 할 것이다ㅠㅠ
템플릿 엔진을 사용하면 HTML 문서에서 필요한 곳만 코드를 적용해서 동적으로 변경할 수 있다❗️
다음 시간엔 JSP로 동일한 작업을 진행할 것이다😄

📌 Welcome 페이지 변경
지금부터 서블릿에서 JSP, MVC 패턴, 직접 만드는 MVC 프레임워크, 그리고 스프링까지 긴 여정을 시작할 것인데
편리하게 참고할 수 있도록 welcome 페이지를 변경하는 과정도 거쳤다😉



🏷 JSP로 회원 관리 웹 애플리케이션 만들기

📌 JSP 라이브러리 추가
build.gradle

//JSP 추가 시작
implementation 'org.apache.tomcat.embed:tomcat-embed-jasper' 
implementation 'javax.servlet:jstl'
//JSP 추가 끝

✔️ main/webapp/jsp/members/new-form.jsp 생성

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <form action="/jsp/members/save.jsp" method="post"> 
        username: <input type="text" name="username" /> 
        age: <input type="text" name="age" /> 
        <button type="submit">전송</button>
    </form>
</body>
</html>

⬆️ <%@ page contentType="text/html;charset=UTF-8" language="java" %> = JSP 문서라는 것을 나타내고, JSP 문서는 이렇게 시작해야 한다


💡 JSP는 자바 코드를 그대로 다 사용할 수 있다
<%@ page import="hello.servlet.domain.member.MemberRepository" %>
➡️ 자바의 import 문과 같다.
<% ~~ %>
➡️ 이 부분에는 자바 코드를 입력할 수 있다.
<%= ~~ %>
➡️ 이 부분에는 자바 코드를 출력할 수 있다.

✔️ main/webapp/jsp/members/save.jsp 회원 저장 JSP

<%--
  Created by IntelliJ IDEA.
  User: jinsol
  Date: 2021/09/05
  Time: 8:21 오후
  To change this template use File | Settings | File Templates.
--%>
<%@ page import="hello.servlet.domain.member.MemberRepository" %>
<%@ page import="hello.servlet.domain.member.Member" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%
    // request, response 사용 가능
    MemberRepository memberRepository = MemberRepository.getInstance();
    System.out.println("save.jsp");

    String username = request.getParameter("username");
    int age = Integer.parseInt(request.getParameter("age"));
    Member member = new Member(username, age);
    System.out.println("member = " + member);
    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>

✔️ main/webapp/jsp/members.jsp 회원 목록 JSP

<%--
  Created by IntelliJ IDEA.
  User: jinsol
  Date: 2021/09/05
  Time: 8:25 오후
  To change this template use File | Settings | File Templates.
--%>
<%@ page import="java.util.List" %>
<%@ page import="hello.servlet.domain.member.MemberRepository" %>
<%@ page import="hello.servlet.domain.member.Member" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%
    MemberRepository memberRepository = MemberRepository.getInstance();
    List<Member> members = memberRepository.findAll();
%>
<html>
<head>
    <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 : members) {
        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>

⬆️ 회원가입으로 2명의 사용자를 만든 뒤 조회 결과👍🏻


서블릿과 JSP의 한계🤔

  • 코드를 잘 보면 JAVA 코드, 데이터를 조회하는 리포지토리 등등 다양한 코드가 모두 JSP에 노출되어 있다
    ➡️ JSP가 너무 많은 역할을 한다,,
  • 이렇게 작은 프로젝트도 벌써 머리가 아파오는데, 수백 수천줄이 넘어가는 JSP를 떠올려보면 정말 지옥과 같을 것이다^_^

MVC 패턴의 등장🥳

  • 보여주는 것과 조종하는 것을 분리해보자❗️
  • 비즈니스 로직은 서블릿처럼 다른곳에서 처리하고,
  • JSP는 목적에 맞게 HTML로 화면(View)을 그리는 일에 집중하도록 하자!

profile
Backend Developer

0개의 댓글