[Spring] CH08 MVC패턴과 스프링 프레임워크 (책)

jaegeunsong97·2023년 2월 27일
0

[Fast Campus] Spring

목록 보기
11/44
post-thumbnail

우리는 왜 Servlet을 사용하지 않고, JSP를 사용하는가?
JSP를 활용하는 방식이 프로그래밍 하기 편하기 때문이다.

그렇다면 이번 시간에는 JSP만 사용하는 방식에는 어떤 문제가 있는지 알아보고 MVC 패턴의 탄생 과정에 대해서 알아보자.

📕 모델 1 방식

모델 1은 뷰와 로직을 모두 JSP 페이지 하나에서 처리하는 구조를 말한다.

https://github.com/codingspecialist/web3

  • 공통 처리가 불가능하다
  • JSP파일에 그림 로직과 비지니스 로직이 함께 들어간다.

📜 Port와 WelcomeFileList 수정

server.xml -> port -> 8080
web.xml -> welcome file list -> index.jsp

📜 모델 1 실습

🔔 DynamicWebProject 생성

  • 프로젝트명 web3

🔔 가짜 DAO 생성

src.shop.mtcoding.web.Board

package shop.mtcoding.web3.model;

public class Board {
    private int id;
    private String title;
    private int userId;

    public Board(int id, String title, int userId) {
        this.id = id;
        this.title = title;
        this.userId = userId;
    }

    public int getId() {
        return id;
    }

    public String getTitle() {
        return title;
    }

    public int getUserId() {
        return userId;
    }
}

src.shop.mtcoding.web.User

package shop.mtcoding.web3.model;

public class User {
    private int id;
    private String username;
    private String password;

    public User(int id, String username, String password) {
        this.id = id;
        this.username = username;
        this.password = password;
    }

    public int getId() {
        return id;
    }

    public String getUsername() {
        return username;
    }

    public String getPassword() {
        return password;
    }
}

src.shop.mtcoding.web.FakeDao

package shop.mtcoding.web3.model;

// Fake DataAccessObject (데이터베이스에 접근하는 클래스)
public class FakeDao {

    public User userData(){
        User u1 = new User(1, "ssar", "1234");
        return u1;
    }

    public Board boardData(){
        Board b1 = new Board(1, "제목1", 1);
        return b1;
    }
}

🔔 JSP 파일 생성

index.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
  <head>
    <title>Model 1</title>
  </head>
  <body>
  <h1>모델1 실습</h1>
  <hr/>
  <p>유저 데이터가 필요하면 user.jsp 호출, 게시글 데이터가 필요하면 board.jsp 호출</p>
  </body>
</html>

user.jsp

<%@ page import="shop.mtcoding.web3.model.User" %>
<%@ page import="shop.mtcoding.web3.model.FakeDao" %>
<%@ page import="java.io.PrintWriter" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>

<%
    String httpMethod = request.getMethod();
    if(httpMethod.equals("POST")){
        response.setContentType("text/html; charset=utf-8");
        PrintWriter pw = response.getWriter();
        pw.println("잘못된 요청입니다");
        return;
    }
    User u1 = new FakeDao().userData();
%>
<html>
<head>
    <title>Model 1</title>
</head>
<body>
    <h1>유저</h1>
    <hr/>
    <h3>번호 : <%=u1.getId()%></h3>
    <h3>유저명 : <%=u1.getUsername()%></h3>
    <h3>비밀번호 : <%=u1.getPassword()%></h3>
</body>
</html>

board.jsp

<%@ page import="shop.mtcoding.web3.model.FakeDao" %>
<%@ page import="shop.mtcoding.web3.model.Board" %>
<%@ page import="java.io.PrintWriter" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>

<%
    String httpMethod = request.getMethod();
    if(httpMethod.equals("POST")){
        response.setContentType("text/html; charset=utf-8");
        PrintWriter pw = response.getWriter();
        pw.println("잘못된 요청입니다");
        return;
    }
    Board b1 = new FakeDao().boardData();
%>
<html>
<head>
    <title>Model 1</title>
</head>
<body>
<h1>게시글</h1>
<hr/>
<h3>번호 : <%=b1.getId()%></h3>
<h3>제목 : <%=b1.getTitle()%></h3>
<h3>작성자 번호 : <%=b1.getUserId()%></h3>
</body>
</html>

🔔 공통 처리 로직이 중복됨

<%
	String httpMethod = request.getMethod();
	if(httpMethod.equals("POST")){
		response.setContentType("text/html; charset=utf-8");
		PrintWriter pw = response.getWriter();
		pw.println("잘못된 요청입니다");
		return;
	}
	Board b1 = new FakeDao().boardData();
%>


📕 FrontController 탄생

FrontContoller 패턴은 지휘자를 만드는 것이다. 여러 클라이언트들의 요청이 있고 해당하는 요청을 처리하는 JSP파일이 있다고 가정하자. 요청을 보낼 때마다 특정한 작업을 하는 것이 필수적이라면 요청이 들어올 때마다 해당 작업을 실어서 보내야 하는데 이 결과 코드의 중복이 생기고 해당 작업을 누락한다면 최악의 경우에는 장애로 이어질 수도 있다.

이러한 까닭에 앞에서 언급한 지휘자가 필요한데 요청을 처리하는 지휘자는 해당 작업을 가지고 있고 해당 작업을 처리한 뒤에 요청에 맞는 JSP에게 전달해주는 역할을 하게 된다. 이것이 바로 FrontController 패턴이다.

https://github.com/codingspecialist/web4.git

  • 공통처리가 가능하다.
  • View가 필요하지 않아도 View를 호출해야 한다.
  • JSP파일에 그림 로직과 비지니스 로직이 함께 들어간다.

📜 FrontController 실습

🔔 DynamicWebProject 생성

  • 프로젝트명 web4

🔔 FrontController 생성

src.shop.mtcoding.web4.FrontController.java

package shop.mtcoding.web4.controller;

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("*.do")
public class FrontController extends HttpServlet {

    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String httpMethod = req.getMethod();
        if(httpMethod.equals("POST")){
            resp.setContentType("text/html; charset=utf-8");
            PrintWriter pw = resp.getWriter();
            pw.println("잘못된 요청입니다");
            return;
        }

        String action = req.getRequestURI();
        System.out.println("uri : "+action);

        if(action.equals("/board.do")){
            resp.sendRedirect("board.jsp");
        }else if(action.equals("/user.do")){
            resp.sendRedirect("user.jsp");
        }else{
            resp.setContentType("text/html; charset=utf-8");
            PrintWriter pw = resp.getWriter();
            pw.println("잘못된 요청입니다");
        }
    }
}

board.jsp

<%@ page import="shop.mtcoding.web4.model.FakeDao" %>
<%@ page import="shop.mtcoding.web4.model.Board" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>

<%
    Board b1 = new FakeDao().boardData();
%>
<html>
<head>
    <title>Model 1</title>
</head>
<body>
<h1>게시글</h1>
<hr/>
<h3>번호 : <%=b1.getId()%></h3>
<h3>제목 : <%=b1.getTitle()%></h3>
<h3>작성자 번호 : <%=b1.getUserId()%></h3>
</body>
</html>

user.jsp

<%@ page import="shop.mtcoding.web4.model.User" %>
<%@ page import="shop.mtcoding.web4.model.FakeDao" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>

<%
    User u1 = new FakeDao().userData();
%>
<html>
<head>
    <title>Model 1</title>
</head>
<body>
    <h1>유저</h1>
    <hr/>
    <h3>번호 : <%=u1.getId()%></h3>
    <h3>유저명 : <%=u1.getUsername()%></h3>
    <h3>비밀번호 : <%=u1.getPassword()%></h3>
</body>
</html>

🔔 user.jsp 다이렉트 호출

🔔 user.do 호출 - FrontController를 통해서!!

📜 FrontController 문제점 살펴보기

문제점 1
user.jsp 를 호출할 수도 있고, user.do를 호출할 수 도 있기 때문에 강제성이 없다.
user.jsp를 다이렉트하게 호출하는 것을 막을 필요가 있다.

문제점 2
jsp 파일에서 쓸데 없는 자바 코드가 많다.

문제점 3
request에 저장된 body 데이터를 유지하려면 세션에 저장하는 방법밖에 없다. 그런데 세션에는 무거운 데이터를 저장하면 좋지 않다.

web4 소스코드를 변경하여 문제점에 대해서 확인해보자

  • 다이렉트하게 호출해보기
  • 자바 비지니스 로직 코드 옮겨보기

세션 데이터 만료
1. 브라우저를 다 종료하면
2. 시간이 만료되면
3. 서버가 껐다가 다시 켜지면
4. 세션을 강제로 제거!!리퀘스트 데이터 만료

📜 3 FrontController 문제점 1,2 해결

https://github.com/codingspecialist/web5.git

🔔 DynamicWebProject 생성

  • 프로젝트명 web5

🔔 JSP 파일 보안폴더에 숨김(WEB-INF)

🔔 RequestDispatcher 사용

RequestDispatcher를 사용하면 request, response가 새로 생기지 않는다.
내부적으로 request와 response를 유지한 채로 재 요청을 한다.

장점
tomcat에 의해서 막히는 WEB-INF 보안 폴더에 접근이 가능하다.

src.shop.mtcoding.web5.controller.FrontController.java

package shop.mtcoding.web5.controller;

import shop.mtcoding.web5.model.Board;
import shop.mtcoding.web5.model.FakeDao;
import shop.mtcoding.web5.model.User;

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("*.do")
public class FrontController extends HttpServlet {

    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String httpMethod = req.getMethod();
        if(httpMethod.equals("POST")){
            resp.setContentType("text/html; charset=utf-8");
            PrintWriter pw = resp.getWriter();
            pw.println("잘못된 요청입니다");
            return;
        }

        String action = req.getRequestURI();
        System.out.println("uri : "+action);

        if(action.equals("/board.do")){
            Board b1 = new FakeDao().boardData();
            req.setAttribute("board", b1);
            req.getRequestDispatcher("/WEB-INF/views/board.jsp").forward(req, resp);
        }else if(action.equals("/user.do")){
            User u1 = new FakeDao().userData();
            req.setAttribute("user", u1);
            req.getRequestDispatcher("/WEB-INF/views/user.jsp").forward(req, resp);
        }else{
            resp.setContentType("text/html; charset=utf-8");
            PrintWriter pw = resp.getWriter();
            pw.println("잘못된 요청입니다");
        }
    }
}

web/WEB-INF/views/board.jsp

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

<html>
<head>
    <title>Model 1</title>
</head>
<body>
<h1>게시글</h1>
<hr/>
<h3>번호 : ${board.id}</h3>
<h3>제목 : ${board.title}</h3>
<h3>작성자 번호 : ${board.userId}</h3>
</body>
</html>

web/WEB-INF/views/user.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Model 1</title>
</head>
<body>
    <h1>유저</h1>
    <hr/>
    <h3>번호 : ${user.id}</h3>
    <h3>유저명 : ${user.username}</h3>
    <h3>비밀번호 : ${user.password}</h3>
</body>
</html>



📕 MVC 패턴

MVC 소프트웨어 디자인 패턴

  1. 모델: 데이터와 비즈니스 로직을 관리합니다.
  2. 뷰: 레이아웃과 화면을 처리합니다.
  3. 컨트롤러: 명령을 모델과 뷰 부분으로 라우팅합니다.

https://github.com/codingspecialist/mvcapp.git

📜 과정

  1. 최초의 요청은 FrontController에게 한다.
    2.FrontController는 공통처리를 하고, 적절한 컨트롤러를 요청한다.
    3.컨트롤러에서 Data가 필요하면 Model에 도움을 받은 뒤 Data를 request에 저장하고 View를 찾아서 응답한다.
  2. 컨트롤러에서 Data가 필요하면 Model에 도움을 받은 뒤 Data를 그대로 응답한다.
  3. 컨트롤러에서 Data가 필요없으면 View를 찾아서 응답한다.
  4. View를 찾을 때는 재 요청(request)이 필요한데, 이를 Redirect라고 한다.
  5. 즉 request가 두 번 만들어진다.
  6. 이 때 문제가 발생한다. request에 저장된 데이터가 날라간다.
  7. RequestDispatcher를 사용하여 request를 유지해야 한다.

📕 프레임워크의 탄생

추운 겨울이 가고 봄이 온다. (스프링 프레임워크)

📜 프레임워크 이해

📜 호밑밭의 파수꾼

📜 라이브러리 vs 프레임워크

📜 협업, 안전성, 보안, 믿을 수 없는 신입

profile
블로그 이전 : https://medium.com/@jaegeunsong97

0개의 댓글