참고글



RequestDispatcher란
RequestDispatcher는 클라이언트로부터 최초에 들어온 요청을 JSP/Servlet 내에서 원하는 자원으로 요청을 넘기는(보내는) 역할을 수행하거나, 특정 자원에 처리를 요청하고 처리 결과를 얻어오는 기능을 수행하는 클래스입니다. 즉 /a.jsp 로 들어온 요청을 /a.jsp 내에서 RequestDispatcher를 사용하여 b.jsp로 요청을 보낼 수 있습니다. 또는 a.jsp에서 b.jsp로 처리를 요청하고 b.jsp에서 처리한 결과 내용을 a.jsp의 결과에 포함시킬 수 있습니다.

요청을 보내는 방법으로는 RequestDispatcher#forward()와 RequestDispatcher#include() 두 가지 방법이 있습니다. 앞으로 이 두가지 방법에 대해 알아보도록 하겠습니다.



RequestDispatcher가 있는 이유. HttpServletResponse#sendRedirect() 와의 차이점
HttpServletResponse를 사용하면 sendRedirect() 메서드를 이용하여 지정한 경로로 제어를 이동시킬 수 있습니다. 그러나 sendRedirect()는 HTTP 리다이렉션을 이용하기 때문에 하나의 요청 범위 안에서 처리를 하는것이 아니라 브라우저에게 Response 후 브라우저측에서 지정받은 요청 경로로 다시 재요청을 하는 방식이기에 두 번의 HTTP 트랜잭션이 발생하며, 서버측에서는 최초에 받은 요청중에 처리한 내용을 리다이렉트 된 요청안에서 공유할 수 없는 문제가 있습니다. 

 

물론 sendRedirect() 에서도 쿠키나 세션등을 이용해 특정 상태를 유지하여 공유할 수는 있겠으나, 상황에 따라 제한적일 수 있으며, 코드 레벨 에서의 알고리즘 등을 곧바로 이어가는데에도 한계가 있기 때문에 좋은 방법이라고 할 수는 없을것입니다.

그대신 HttpServletResponse를 통해 리다이렉트 하는 방식은 현재 어플리케이션 이외에 다른 자원의 경로를 요청할 수 있는 반면 RequestDispatcher는 현재 처리중인 서블릿이 속해 있는 웹 어플리케이션 범위 내에서만 요청을 제어할 수 있습니다.






RequestDispatcher 생성(얻는) 방법
RequestDispatcher는 ServletContext나 ServletRequest 클래스에서 제공하는 팩토리 메서드(Factory Method)를 통해 얻을 수 있습니다. 팩토리 메서드라는 용어에 대해서는 이 글의 범위 밖이므로 디자인 패턴을 참고해 주시기 바랍니다. 

ServletContext을 통해서 얻는 법
서블릿 클래스에서 ServletContext를 사용하여 RequestDispatcher를 얻을 수 있습니다.

호출 대상을 web.xml에 지정한 서블릿 이름(<servlet-name>)으로 지정하는 방법
ServletContext context = this.getServletContext(); 
RequestDispatcher dispatcher = context.getNamedDispatcher("helloServlet");                 
cs
 
호출 대상을 URL 경로로 지정하는 방법. 웹어플리케이션 루트경로를 기준으로 절대경로만 지정할 수 있습니다.
ServletContext context = this.getServletContext(); 
RequestDispatcher dispatcher = context.getRequestDispatcher("/hello");                     
cs

JSP 페이지에서는 application 기본객체를 이용합니다.
<%
     RequestDispatcher dispatcher = application.getRequestDispatcher("/hello");             
%>
cs


ServletRequest를 통해서 얻는 법
서블릿 클래스에서는 service() 메서드나 doGet() doPost() 등에서 ServletRequest의 하위 클래스인 HttpServletRequest를 매개변수로 받기 때문에 이것을 이용하여 RequestDispatcher를 얻을 수 있습니다. HttpServletRequest에서는 URL 경로를 통해서 대상을 지정하는 한가지 방법만을 제공합니다. 그러나 ServletContext를 통해서 대상을 지정할때와는 다르게 절대경로 및 상대경로 모두 지정이 가능합니다. JSP 페이지에서도 ServletRequest의 인스턴스인 request 기본객체가 있으므로 쉽게 얻을 수 있습니다.
RequestDispatcher dispatcher = request.getRequestDispatcher("/hello");                    
cs





RequestDispatcher의 forward() 메서드
forward() 메서드는 대상 자원으로 제어를 넘기는 역할을 합니다. 브라우저에서 /a.jsp로 요청했을 때 /a.jsp에서 forward()를 실행하여 /b.jsp로 제어를 넘길 수 있습니다. 제어를 넘겨받은 /b.jsp는 처리 결과를 최종적으로 브라우저에게 출력합니다. 브라우저 입장에서는 /a.jsp를 요청했지만 받은 결과는 /b.jsp의 결과입니다. 이때 HTTP 리다이렉트 방식과는 달리 하나의 HTTP 요청(Request) 범위 안에서 동작이 이루어집니다.






forward() 메서드 실습
forward()는 특정 자원으로 제어를 넘긴다고 했는데 대상 자원은 Servlet 또는 JSP 페이지가 됩니다(JSP도 결국은 최종적으로 서블릿이므로). 여기서는 서블릿으로 실습을 진행하지만 JSP페이지에서도 application이나 request 내장객체를 통해서 RequestDispatcher 를 얻어 forward()를 실행할 수 있습니다. 다음과 같이 DispatchTest(/dispatch) -> HelloServlet(/hello) 로 forward()를 실행하는식으로 진행합니다.


DispatchTest 서블릿이고 URL은 /dispatch로 맵핑합니다. RequestDispatcher를 통해 /hello자원으로 forward()를 실행하는데 /hello는 HelloServlet입니다. 이때 request에 사전처리로 name 속성에 "dololak"을 담았습니다. forward()는 제어가 넘어간 이후 다지 이전의 자원으로 제어가 돌아가지 않으므로 호출하는쪽의 처리를 모두 완료한 후 제어를 넘겨야 합니다. forward() 실행시에는 HttpServletRequest와 HttpServletResponse 객체를 같이 넘겨주기 때문에 호출한 쪽과 호출당한 쪽에서 이 두 가지의 객체를 공유합니다.
public class DispatchTest extends HttpServlet { 
     @Override 
     protected void service(HttpServletRequest request, HttpServletResponse response) 
                                                    throws ServletException, IOException { 
           request.setCharacterEncoding("UTF-8"); 
           request.setAttribute("name""doloak"); //사전처리 
           
           RequestDispatcher dispatcher = request.getRequestDispatcher("/hello"); 
           dispatcher.forward(request, response); 
     }
}
cs


HelloServlet은 /hello에 맵핑되어있는 서블릿입니다. /dispatch로 호출된 DispatchTest 서블릿에서 forward()를 통해 제어가 넘어옵니다. DispatchTest에서 forward()를 실행하기 전에 담아두었던 name 속성값을 꺼내어 브라우저로 출력합니다.
public class HelloServlet extends HttpServlet { 
     @Override 
     protected void service(HttpServletRequest request, HttpServletResponse response) 
                                                    throws ServletException, IOException { 
        response.setContentType("text/html; charset=utf-8"); 
 
 
        PrintWriter out = response.getWriter(); 
        out.println("<HTML>"); 
        out.println("<head><title>HELLO</title></head>"); 
        out.println("<body>"); 
        out.println("HELLO " + request.getAttribute("name")); 
        out.println("</body>"); 
        out.println("</html>"); 
     }
}
cs


web.xml 서블릿 맵핑정보입니다.
<servlet>
     <servlet-name>dispatchServlet</servlet-name>
     <servlet-class>com.dololak.servlet.DispatchTest</servlet-class>                    
</servlet>
<servlet-mapping>
     <servlet-name>dispatchServlet</servlet-name>
     <url-pattern>/dispatch</url-pattern>
</servlet-mapping>
 
 
<servlet>
     <servlet-name>helloServlet</servlet-name>
     <servlet-class>com.dololak.servlet.HelloServlet</servlet-class>
</servlet>
<servlet-mapping>
     <servlet-name>helloServlet</servlet-name>
     <url-pattern>/hello</url-pattern>
</servlet-mapping>
cs


브라우저로 최종 호출된 내용입니다.  여기서는 사전처리시에 name 속성만을 넘겨주었지만 실무에서는 forward()기능을 다양한 용도로 활용할 수 있습니다.



forward() 사용시 주의할 점
forward()는 제어를 넘기기 이전에 출력 버퍼를 비우기 때문에 a.jsp -> b.jsp로 호출시 a.jsp에서 어떤 내용을 버퍼에 출력했더라도 무시되며 제어가 넘어간 b.jsp의 출력 내용만 브라우저에게 전달되므로 주의하도록 합니다.

 

 

JSP 페이지에서 사용시
JSP 페이지에서 사용시에도 전혀 다를게 없으며, 기본객체들을 이용하면 됩니다. 
<%
    RequestDispatcher dispatcher = application.getRequestDispatcher("/hello");            
    dispatcher.forward(request, response);
%>
cs

 




다음글
블로그 이미지

도로락

IT, 프로그래밍, 컴퓨터 활용 정보 등을 위한 블로그

댓글을 달아 주세요! 질문 환영합니다!