스테이트리스(Stateless)란?
시스템이나 프로토콜이 이전에 받았던 요청의 정보를 저장하지 않고 각 요청을 별개의 것으로 처리하는 것이다. 즉 상태 정보가 저장되지 않는다.
- webapp → WEB-INF로 파일 이동 → 강제성을 주기 위해서 한다.
필요하면 302로 다 리다이렉션을 때린다.
이러면 JSP 파일이 필요 없다 이래서 Controller는 class 파일로 만든다.
요청시마다 리퀘스트 리스폰스를 만든다. → 상태를 저장하지않는다. → 2번 만들어진다.
→ 최초에 요청한 데이터 없음. → 내부 호출을 해야한다.
→ (1요청 2내부에서 다시 요청 3전달) 순서
무조건 디스패쳐를 거쳐서 가야하므로 그런 것이다.
최초에 들고있는 req, resp를 들고 재요청을 한다. 강제성을 주기위해 하는 것이다. WEB-INF가 보안 폴더 이기 때문이다. → 내부적으로 통신할때는 가방을 두고 가는데 이 이유가 스테이트 리스 때문이다.
( 구조도 노출이 안됨 )
라우터를 이해하기 위한 코드
DispatcherServlet (라우터)
package com.example.userapp.config;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
// FromtController
// 라우터
@WebServlet("*.do") // ~.do 하면 여기로 다 오는 것
public class DispatcherServlet extends HttpServlet {
// /join-form.do
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 1. 공통로직
resp.setHeader("Content-Type", "text/html; charset=utf-8");
System.out.println("common logic~~~~~");
// 2. 분기
String uri = req.getRequestURI();
if (uri.equals("/join-form.do")) {
//resp.sendRedirect("/WEB-INF/user/join-form.jsp");
req.getRequestDispatcher("/WEB-INF/user/join-form.jsp").forward(req, resp); // 최초에 들고있는 req, resp를 들고 재요청을 한다. 강제성을 주기위해 하는 것이다. WEB-INF가 보안 폴더 이기 때문이다.
} else if (uri.equals("/join.do")) {
//resp.sendRedirect("/WEB-INF/user/join.jsp");
req.getRequestDispatcher("/WEB-INF/user/join.jsp").forward(req, resp);
} else if (uri.equals("/main.do")) {
//resp.sendRedirect("/WEB-INF/board/main.jsp");
req.getRequestDispatcher("/WEB-INF/board/main.jsp").forward(req, resp);
} else {
resp.setStatus(404);
resp.getWriter().println("잘못된 페이지를 요청하셨습니다.");
}
}
}
join
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%
// username=ssar&password=1234&email=ssar@gmail.com
//response.setHeader("Content-Type", "text/html; charset=utf-8"); // body의 header에 타입을 알려주는 방법! 이래야 한글 안깨짐
// 1. 파싱(parsing)
String username = request.getParameter("username"); // 톰캣에서 제공하는 파싱!
String password = request.getParameter("password");
String email = request.getParameter("email");
System.out.println("username : " + username);
System.out.println("password : " + password);
System.out.println("email : " + email);
// 2. 유효성 검사 (1000줄 됨)
if (username.length() < 3 || username.length() > 10) { // 필터링 하듯!
response.getWriter().println("<h1>username 글자수가 3~10 사이여야 합니다</h1>");
return;
}
// 3. DB 연결
// 4. DAO의 insert 메서드를 호출
// 5. 메인 페이지 그리기 (비효율적)
// 6. 리다이렉트(Redirect) -> 안 쓰면 HTML 코드를 통째로 또 넣어야 해서 엄청나게 긴 코드가 되서 지저분해진다.
//resp.sendRedirect("/main"); // 5의 메인 페이지 그리기는 간략화해서 하는 방법이라 보면 된다.
// 위의 sendRedirect를 풀어 쓰면 아래의 두 줄이다.
response.setStatus(302); // 프로토콜로 상태코드가 302여야 리다이렉트가 가능하다.
response.setHeader("Location", "main.do");
//response.setHeader("clock", "12pm");
%>
join-form
<%@ page import="java.time.LocalDateTime" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%
LocalDateTime now = LocalDateTime.now();
%>
<html>
<head>
<title>Title</title>
</head>
<body>
<h1>회원가입 페이지 <%=now%>
</h1>
<hr>
<form action="/join.do" method="post">
<input type="text" placeholder="username" name="username">
<input type="text" placeholder="password" name="password">
<input type="text" placeholder="email" name="email">
<button>회원가입</button>
</form>
</body>
</html>
main
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<h1>main page</h1>
<hr>
</body>
</html>
이 코드에서 보면 WEB-INF인 보안 폴더에 넣는데 이유는 강제성을 부여하기 위해서 이다!
이때는 리다이렉션이 안 먹는데 계속 막히기 때문에 내부적으로 요청을 해야 한다.
그로 인해 “forward”를 사용한다.
req.getRequestDispatcher("/WEB-INF/user/join-form.jsp").forward(req, resp); // 내부적 요청을 해서 보안을 유지한다
리다이렉션과 포워딩의 차이
리다이렉션(Redirection)과 포워딩(Forwarding) 사용자의 요청을 처리하는 두 개의 방식!
리다이렉션
- 클라이언트에게 다른 URL로 이동하라고 지시
- 브라우저 주소 창의 URL이 변경됨
- 두 번의 네트워크 요청이 발생 (리스폰스와 리퀘스트가 두 번 생김)
포워딩
- 서버 내부에서 요청을 다른 서블릿/JSP로 전달
- 브라우저 주소 창의 URL이 그대로 유지됨
- 한 번의 네트워크 요청으로 처리 (리스폰스와 리퀘스트가 한 번 생김)
fowarding = 덮어씌기
포워딩은 결국 확인!
결론
두개의 차이점은
리다이렉션은 디스패처 서블릿(프론트 컨트롤러)를 통해서 요청이 반환 되는 경우 말고도 각 컨트롤러를 통해서 반환 되는 것 을 얘기하고(url 변경)포워딩은 디스패처 서블릿을 통해서만 클라이언트의 요청 결과가 반환 되어 실제로는 서버 내부에서 다른 페이지로 이동한다. 그러나 이를 클라이언트의 입장에서는 같은 url을 화면에 출력함으로써 눈치채지 못하게 할 뿐 이다.
이유는 보안 문제이다.
Share article