<< 학습 목표 >>
1. RequestDispatcher 를 사용해 포워딩 할 수 있다.
앞서 두 가지 포워딩 방법 중 첫 번째 포워딩 방법을 배웠음
1. 클라이언트에게 이동할 곳을 지정해주는 방법
2. 서버 안에서 이동하는 방법
이번에는 두 번째 포워딩 방법인 [ 서버 안에서 이동하는 방법 ] 을 배워보자
두 번째 포워딩 방법은 아래 그림과 같이 "복잡한 포워딩" 임
아래 그림과 같이 동작하는 포워딩이 아닌 지금 배울 포워딩은 "복잡한 포워딩" 이라고 생각하면 됨
그렇다고 해서 어렵거나 진짜 복잡하지는 않고 첫 번째 포워딩 방법 보다 서버에서 할 것이 늘어난 것

전에 했던 포워딩과 이 포워딩의 차이는 클라이언트가 포워딩 됐다는걸 아느냐 모르느냐임
클라이언트는 포워딩 됐다는걸 어떻게 알까? 브라우저의 URL이 바뀌느냐 안바뀌느냐로
전에 했던 포워딩을 하게 되면 요청했던 URL과 결과를 보고 있는 페이지의 URL이 다르므로 클라이언트가 "포워딩(이동) 됐구나" 를 알 수 있지만 이번 방법을 사용하게 되면 요청했던 URL은 그대로이지만 결과를 보고 있는 페이지는 상황에 맞는 적절한 페이지가 보여짐
<< 서버 안에서 이동하는 방법 >>
이 포워딩의 좀 더 적절한 예를 들자면 분업을 예로 들 수 있음
앞서 서블릿으로 클라이언트에게 "결괏값을 담고 있는 페이지" 를 전달하기가 굉장히 불편했음
Spring 또는 실무의 웹 프로젝트에서는 서블릿이 클라이언트의 요청을 받아 처리하고 클라이언트에게 상태 코드와 결괏값을 전달해야한다면 그대로 서블릿에서 응답하지만 "결괏값을 담고 있는 페이지" 를 전달할 때는 그 처리를 JSP에게 넘김

1. 클라이언트가 서버에게 요청함
2. 결괏값을 전달해야한다면 서블릿이 클라이언트에게 결괏값을 전달함
3. 결과 페이지를 전달해야한다면 서블릿이 여기서 배울 포워딩 방법(RequestDispatcher) 를 사용해 JSP로 포워딩함
4. JSP 로 만들어진 결과 페이지를 클라이언트에게 전달함
이렇게 서블릿으로 해결하기 어렵거나 불편한 부분을 다른 곳으로 넘겨주는 방법이 여기서 배울 포워딩 방법임
이 방법은 요청 정보(HttpServletRequest) 안에 들어있는 RequestDispatcher 를 꺼내서 포워딩을 하는 방법임
바로 RequestDispatcher 를 사용한 포워딩 코드를 보자
우선 웹 페이지부터 추가하자
webapp -> chapter04 -> request.html 을 만들고 아래 코드를 입력하자
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>RequestDispatcher 방식 포워딩</title>
</head>
<body>
<a href="/studyProject/chapter04/forwarding_1">서버로 요청을 보냄</a>
</body>
</html>
이 페이지는 굉장히 간단한 페이지로 a 태그를 사용해 서버로 요청을 보냄
이때 우리가 어느 서버로 요청을 보내는지 a 태그의 href 속성을 잘 보자
이번에는 요청을 받을 서블릿을 추가하자
chapter04 -> Forwarding1 서블릿을 추가하고 아래 코드를 추가하자
package chapter04;
import java.io.IOException;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/chapter04/forwarding_1")
public class Forwarding1 extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("Forwarding1 서블릿의 doGet 메서드 호출됨");
RequestDispatcher rd = request.getRequestDispatcher("/chapter04/forwarding_2");
rd.forward(request, response);
}
}
또 chapter04 -> Forwarding2 서블릿을 추가하고 아래 코드를 추가하자
package chapter04;
import java.io.IOException;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/chapter04/forwarding_2")
public class Forwarding2 extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("Forwarding2 서블릿의 doGet 메서드 호출됨");
}
}
웹 페이지에서 [ 서버로 요청을 보냄 ] 을 클릭하면 Forwarding1 서블릿의 doGet 메서드가 동작해 "Forwarding1 서블릿의 doGet 메서드 호출됨" 이 출력됨(1)
그 후 클라이언트 몰래 포워딩을 하기 위해 RequestDispatcher 를 사용해 포워딩을 하고 있음
먼저 요청 정보(HttpServletRequest) 안에 들어있는 RequestDispatcher 객체를 꺼내는데(2) 이때 RequestDispatcher 를 통해서 이동할 다음 서블릿의 경로를 지정해줘야함(3)
꺼낸 RequestDispatcher 객체의 forward 메서드를 사용해서 포워딩을 하고 있음(4)

RequestDispatcher 방식으로 포워딩을 하면 클라이언트에게 응답이 가는게 아닌 그 다음 서블릿(/chapter04/forwarding_2) 의 doGet 메서드가 호출됨

서블릿(Forwarding2)의 doGet 메서드가 동작해 "Forwarding2 서블릿의 doGet 메서드 호출됨" 이 출력되고 난 후에 Forwarding2 서블릿이 클라이언트에게 응답을 함
처음 웹 페이지에서 [ 서버로 요청을 보냄 ] 을 클릭해 클라이언트는 forwarding_1 서블릿으로 요청을 보냈음
요청을 받은 서블릿 내부에서는 RequestDispatcher 를 사용해서 forwarding_2 서블릿으로 처리를 넘겼음
그러나 웹 페이지의 URL은 여전히 forwarding_1 임
이렇게 RequestDispatcher 를 사용하면 클라이언트의 URL이 바뀌지 않기 때문에 내부에서 어떤 동작이 이뤄지는지 알지 못한다는 특징이 있음
브라우저의 URL을 확인해보자

브라우저에서는 왜 빈 화면만 보일까??
우리는 두 번째 서블릿에서 Sysout만 하고 있지 "상태 코드" 또는 "결괏값"을 전달하거나 "결괏값을 담은 페이지"를 전달하지 않고 있기 때문에 클라이언트 페이지에서 보이는건 아무것도 없음

여기까지 RequestDispatcher의 내용 끝~!
이번에는 지금까지 배운 포워딩 방법을 활용해보자
이 전 글에서 배운 포워딩 방법과 이번에 배운 포워딩 방법을 다 사용함
이 글의 서론에서 실무에서는 서블릿의 RequestDispatcher와 JSP를 사용한다고 했음
우리는 아직 JSP를 배우지 않았기 때문에 서블릿과 HTML을 사용해보자
로그인 페이지와 로그인 서블릿, 로그인 결과를 보여줄 페이지 이 세 개를 사용한 로그인 서비스를 만들자
사용자는 로그인 웹 페이지에서 아이디, 비밀번호를 입력하고 [ 로그인 ] 버튼을 누름(1)
로그인 서블릿은 로그인 요청을 받고 로그인 처리를 함(2)
이때, 로그인에 성공했다면 로그인 성공 페이지로 포워딩함(3)
로그인에 실패했다면 로그인 페이지에 GET 방식으로 status 파라미터를 붙여 로그인 페이지로 포워딩함(4)

먼저 로그인 웹 페이지를 만들자
webapp -> chapter04 -> login4.html 을 추가하고 아래 코드를 입력하자
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>로그인</title>
<style type="text/css">
p {color: red; display: none;}
</style>
</head>
<body>
<form action="/studyProject/chapter04/login_4" method="POST">
아이디: <input type="text" name="id"><br>
비밀번호: <input type="password" name="pw"><br>
<p>아이디 또는 비밀번호를 확인하세요.</p>
<input type="submit" value="로그인">
</form>
<script type="text/javascript">
let parameter = location.search;
if(parameter != '') {
parameter = parameter.split("=");
let name = parameter[0];
let value = parameter[1];
if(name == "status" && value == "fail") {
let pTag = document.querySelector("p");
pTag.style.display = "";
}
}
</script>
</body>
</html>
사용자가 로그인 페이지에 접근하면 아이디, 비밀번호, [ 로그인 ] 버튼이 보임
p 태그는 display: none 으로 해뒀기 때문에 보이지 않음
이 웹 페이지는 위 동작 과정 그림의 (1), (4) 를 담당함
사용자에게 아이디, 비밀번호를 입력 받고 [ 로그인 요청 ] 을 서버로 보낼 수 있게 해주는 페이지(1) 이고 사용자가 아이디 또는 비밀번호를 잘못 입력해 로그인에 실패했을 경우에는 서버가 보내준 GET 파라미터를 꺼내서 status 파라미터 값이 fail일 경우에는 로그인 실패 메세지(아이디 또는 비밀번호를 확인하세요.) 를 보여주는 페이지(4) 임
만약 사용자가 웹 개발자라면 이 웹 페이지를 열어보면 페이지 내 JS 코드를 해석할 수 있을 것
그리고 로그인 페이지의 URL 뒤에 GET 방식으로 status=fail 파라미터를 붙인다면 p 태그가 보여 "아이디 또는 비밀번호를 확인하세요." 가 보일 것
로그인 웹 페이지를 이용하는 사용자는 웹 개발을 모르는 사람이라고 하겠음
로그인 요청을 받을 서블릿을 만들자
chapter04 -> login4 서블릿을 추가하고 아래 코드를 입력하자
package chapter04;
import java.io.IOException;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/chapter04/login_4")
public class Login4 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String id = request.getParameter("id");
String pw = request.getParameter("pw");
String tempId = "myId";
String tempPw = "myPw";
if(id.equals(tempId) && pw.equals(tempPw)) {
RequestDispatcher rd = request.getRequestDispatcher("/chapter04/loginSuccess.html");
rd.forward(request, response);
} else {
response.sendRedirect("/studyProject/chapter04/login4.html?status=fail");
}
}
}
이 서블릿에서 살펴볼 것이 두 가지 있음
1. 로그인 성공의 경우와 로그인 실패의 경우 포워딩 하는 방식이 다름
2. 로그인 성공의 경우 포워딩 경로가 /chapter04 로 시작하고 로그인 실패의 경우 포워딩 경로가 /studyProject 로 시작함
<< 로그인 성공의 경우와 로그인 실패의 경우 포워딩 하는 방식이 다름 >>
로그인에 성공했을 경우 RequestDispatcher 를 사용해 포워딩하고 있는데 왜그럴까?
특별한 이유는 없음
그저 우리가 여기서 RequestDispatcher 를 배웠기 때문에 사용한 것
로그인에 실패했을 경우 sendRedirect 를 사용해 포워딩하고 있는데 왜그럴까?
특별한 이유는 없음
그저 사용하고 싶어서 사용했을 뿐
로그인에 성공했을 경우 서블릿 자체에서 로그인 성공 페이지를 전달하도록 PrintWriter 객체를 꺼내서 로그인 성공 페이지를 print 해도되고 포워딩을 할 때는 앞서 배운 세 가지와 여기서 배운 한 가지 중 어느 것을 사용해도 상관 없음
로그인에 실패했을 때도 마찬가지로 서블릿 자체에서 로그인 실패 페이지를 전달하도록 PrintWriter 객체를 꺼내서 로그인 실패 페이지를 print 해도 되고 포워딩을 할 때는 앞서 배운 세 가지와 여기서 배운 한 가지 중 어느 것을 사용해도 상관 없음
<< 로그인 성공의 경우 포워딩 경로가 /chapter04 로 시작하고 로그인 실패의 경우 포워딩 경로가 /studyProject 로 시작함 >>
RequestDispatcher 를 사용할 때는 URL에서 프로젝트 경로(http://localhost:8080/studyProject)까지는 반드시 생략해야함
서버 자체에서 포워딩을 하기 때문에 프로젝트 경로까지는 알고 있어서 생략해야함
만약 프로젝트 경로를 붙이면 문제가 생김
앞서 배운 세 가지 방식은 클라이언트에게 "여기로 가!" 라고 지시한것이기 때문에 정확하게 입력한다면 프로토콜(http)부터 써야함
브라우저는 URL에 프로토콜 ~ 포트번호까지(http://localhost:8080) 을 생략하면 현재 페이지의 프로토콜 ~ 포트번호까지 자동으로 붙여서 사용한다고 했음
그래서 sendRedirect 로 포워딩을 했을 때는 브라우저가 서버의 지시를 받고 전달 받은 URL의 앞에 "http://localhost:8080" 을 붙여서 이동함
이제 서버를 실행시키고 로그인 페이지에 접근해서 아이디, 비밀번호를 정확하게 입력했을 때 결과와 URL을 확인하자

이번에는 아이디와 비밀번호를 다르게 입력하고 결과와 URL을 확인하자

여기까지 포워딩 방식을 사용해서 조금 더 실무에 가까운 로그인 페이지를 만들어봤음
이 카테고리(Servlet)에서는 서블릿만 배우기 때문에 실무와 똑같은 프로젝트를 할 수는 없지만 이 카테고리의 마지막에 서블릿에서 배운 모든걸 활용해서 간단한 서비스를 만들어 볼 예정임
'Servlet + JSP > Serlvet-Chapter04' 카테고리의 다른 글
| Chapter04. ServletContext (0) | 2023.03.03 |
|---|---|
| Chapter04. 포워딩을 할 때 값을 전달하는 방법 (0) | 2023.03.03 |
| Chapter04. 포워딩(Forwarding) / 클라이언트에게 "여기로 가!" 지시하기 (0) | 2023.03.02 |
| Chapter04. 클라이언트에게 JSON 데이터 전달하기 (0) | 2023.03.02 |
| Chapter04. 클라이언트에게 상태 코드 담아 전달하기 (0) | 2023.03.02 |