3 분 소요

서블릿을 이용하여 사용자 요청을 처리한 뒤에는 다른 페이지로 이동해야할 일도 있을 것이다. 예를 들어, 회원 가입을 완료했다면 다시 로그인 화면으로 이동하게 하는 것이다.

서블릿에서는 페이지 이동 기술로 두 가지 방식이 제공된다. redirect와 forwarding이다.

Redirect

서블릿 내에서 redirect를 이용하려면 HttpServiceResponse 객체의 sendRedirect(”경로”) 메서드를 이용하면 된다. 해당 메서드를 호출하는 순간, 실행 중인 서블릿이 중단되고 클라이언트로 응답이 전송된다.

redirect의 동작 원리는 다음과 같다.

  • 서블릿 내 response.sendRedirect(”경로”) 메서드를 호출하게 되면 실행 중이던 서블릿이 중단되고, 클라이언트에 즉시 응답을 전송한다.
  • 이 때 이 응답은 클라이언트에 전송되면 클라이언트가 sendRedirect 메서드의 인자로 전달된 경로를 자동으로 재요청하도록 설정되어 있다.
  • 이로 인해, 응답을 전송받은 클라이언트는 자동으로 redirect로 지정된 새 경로를 서버에 재요청하게 된다.
  • 재요청 받은 서버는 지정된 경로에 해당하는 응답 페이지를 다시 클라이언트에게 전송하여 보여준다.

redirect 동작 원리를 그림으로 그려보았다.

redirect 동작 원리를 그림으로 그려보았다.

redirect에는 다음의 사실들이 있다.

  • redirect는 요청과 응답 사이클이 두 번이나 반복되기에 실행 속도가 느리다.
  • redirect시 브라우저의 URL이 뒤바뀐다. 이로 인해 사용자는 다른 페이지로 이동했다는 사실을 인지할 수 있다.

다음은 서블릿에서 redirect를 살펴보는 예제이다.


import java.io.IOException;
import java.io.PrintWriter;

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("/redirect.do")
public class RedirectServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;

	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		request.setCharacterEncoding("utf-8");
		response.setCharacterEncoding("euc-kr");
		
		PrintWriter out = response.getWriter();
		
		out.println("<html><body>");
		out.println("<h1>다른 페이지로 redirect하기</h1>");
		out.println("</body></html>");
		
		try {
			Thread.sleep(3000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		
		response.sendRedirect("/response.do");
		
		out.close();
	}

	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		doGet(request, response);
	}

}

RedirectServlet.java


import java.io.IOException;
import java.io.PrintWriter;

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("/response.do")
public class ResponseByRedirectServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;

	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		request.setCharacterEncoding("utf-8");
		response.setCharacterEncoding("euc-kr");
		
		PrintWriter out = response.getWriter();
		
		out.println("<h1>redirect된 곳입니다.</h1>");
		out.println("redirect의 요청 방식 : " + request.getMethod());
		out.close();
	}

	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		request.setCharacterEncoding("utf-8");
		response.setCharacterEncoding("euc-kr");
		
		PrintWriter out = response.getWriter();
		
		out.println("<h1>redirect된 곳입니다.</h1>");
		out.println("redirect의 요청 방식 : " + request.getMethod());
		out.close();
	}

}

ResponseByRedirectServlet.java

RedirectServlet.java를 실행하면 다음의 결과를 얻는다.

20240905_06504104.png

20240905_06504388.png

약 3초 뒤에 redirect하게 설정하였다. redirect 전과 후의 URL이 다름을 알 수 있다.

Forwarding (포워딩)

forwarding도 redirect와 같은 페이지 이동 기술이지만, redirect와는 동작 방식이 다르다.

forwarding의 동작 방식

  1. 클라이언트가 서버에 요청을 한다.
  2. 최초 요청을 받은 서블릿은 요청 처리 후, 다른 응답 페이지를 보여주기 위해 서버 안에서 다른 서블릿으로 forwarding하여 요청한다.
  3. forwarding 대상이 된 서블릿에서 응답 페이지를 생성하여 이를 클라이언트에 전송한다.

forwarding의 동작 원리를 그림으로 그려보았다.

forwarding의 동작 원리를 그림으로 그려보았다.

forwarding에 대해 다음의 사실들이 있다.

  • 서버 안에서 페이지 이동이 일어나는 것이라 redirect에 비해 요청-응답 사이클이 절반으로 줄어드는 것을 위 그림들을 통해 알 수 있다. 따라서 상대적으로 실행 속도가 빠른 편이다.
  • 사용자 입장에서는 브라우저에 보여지는 URL이 변경되지 않는다. 따라서 사용자는 페이지가 이동되었는지 알기 어렵다.

서블릿에서는 HttpServletRequest 객체의 getRequestDispatcher(”path") 메서드를 포워드 요청할 경로와 함께 호출하면 RequestDispatcher 객체의 메모리 주소를 반환받을 수 있다. 이를 참조 변수로 받은 후, 해당 변수에서 forward(request, response) 메서드를 호출하면 지정한 경로로 포워딩된다. 다음은 이를 활용한 예제이다.

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	<h1>포워딩</h1>
	<form action="forward.do" method="post">
		<input type="submit" value="포워딩 체험하기" />
	</form>
</body>
</html>

forwarding.html


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("/forward.do")
public class ForwardServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;
	
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		goForward(request, response);
	}

	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		goForward(request, response);
	}
	
	protected void goForward(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		RequestDispatcher dispatcher = request.getRequestDispatcher("forwardTarget.do");
		dispatcher.forward(request, response);
	}
}

ForwardServlet.java


import java.io.IOException;
import java.io.PrintWriter;

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("/forwardTarget.do")
public class ForwardTargetServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;

	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		handleForward(request, response);
	}

	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		handleForward(request, response);
	}
	
	protected void handleForward(HttpServletRequest request, HttpServletResponse response) throws IOException {
		request.setCharacterEncoding("utf-8");
		response.setCharacterEncoding("euc-kr");
		
		PrintWriter out = response.getWriter();
		
		out.println("<html><body>");
		out.println("<h1>반갑습니다.</h1>");
		out.println("<p>받은 요청의 메서드 방식 : " + request.getMethod() + " </p>");
		out.println("</body></html>");
		out.close();
	}

}

ForwardTargetServlet.java

forwarding.html을 실행하면 다음의 결과를 얻는다.

스크린샷 2024-09-05 183303.png

스크린샷 2024-09-05 183311.png

첫 화면에서 사용자가 버튼을 클릭하여 처음에는 forward.do로 이동한다. 그런데 해당 서블릿의 내용을 보면…

protected void goForward(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
	RequestDispatcher dispatcher = request.getRequestDispatcher("forwardTarget.do");
	dispatcher.forward(request, response);
}

포워딩만 할 뿐 아무런 화면도 출력하게끔 하고 있지 않다. 위 두 번째 사진의 화면은 forwardTarget.do와 매핑된 ForwardTargetServlet 서블릿이 출력해주는 것이다. 즉, 결과적으로는 forwardTarget.do로 페이지 이동이 된 것이다.

그런데 위 결과의 두 번째 사진의 브라우저 URL을 보면 forwardTarget.do가 아닌 forward.do임을 알 수 있다. 즉, 포워딩 방식은 브라우저 상에서 URL이 바뀌지 않아 사용자가 다른 페이지로 이동했는지 알 수 없다. 위 예제에서는 사용자는 forwardTarget.do라는 경로의 존재를 알지 못할 것이다.


References

[1] 에이콘아카데미(강남) 강의

[2] 채규태, “채쌤의 Servlet&JSP 프로그래밍 핵심”, (쌤즈, 2023)

This content is licensed under CC BY-NC 4.0

댓글남기기