본문 바로가기
웹 프로그래밍/Servlet & JSP

Servlet HttpServletRequest 상태정보 공유(요청 재지정 Redirection)

by kgvovc 2021. 3. 12.
반응형

HttpServletRequest

이번 절에서 HttpServletRequest 객체를 사용하여 여러 페이지 간에 정보를 공유하는 방법을 학습하겠습니다.

 

HttpServletRequest 객체에 여러 페이지에서 공유할 정보를 저장한다 하더라도 service() 메소드가 종료되는 시점에 HttpServletRequest 객체도 소멸할 텐데 그곳에 정보를 저장하는 의미가 있을까요?

 

HttpServletRequest 객체는 하나의 서블릿 페이지가 실행되는 동안에만 메모리에 존재하는 개체이기 때문에 HttpServletRequest를 통해 정보를 유지하는 것은 무의미하다고 생각할 겁니다.

 

그런데 아직 학습하지 않은 내용 중에 클라이언트가 서블릿 실행 요청을 했을 때 하나의 페이지만 실행되는 것이 아니라 여러 페이지가 실행될 수 있는 상황이 발생할 수 있습니다.

 

 

 

그림 출처: https://tmxhsk99.tistory.com/135

 

 

위 그림은 클라이언트의 요청 한 번으로 두 개의 페이지가 실행된 모습입니다. 클라이언트가 A 페이지를 요청했는데 A 페이지가 실행되면서 B 페이지로 이동하여 B 페이지도 실행된 모습입니다. 즉, 한 번의 클라이언트 요청으로 여러 페이지가 실행된 것입니다. HttpServletRequest 객체를 통해 정보를 유지하는 예는 이처럼 한 번의 요청으로 실행된 페이지 간에 데이터를 공유하고자 할 때 사용하는 방법입니다.

 

위의 그림처럼 클라이언트가 A 페이지를 요청하고, A 페이지에서 B 페이지로 이동했을 때는 A와 B 페이지가 동일한 HttpServletRequest와 HttpServletResponse 객체를 사용하지만, 클라이언트가 B 페이지를 직접 실행 요청했을 때는 새로운 객체가 생성되므로 A 페이지와는 상관없는 객체를 사용하게 됩니다. 그래서 이때는 HttpServletRequest를 통해 정보를 공유할 수 없습니다.

 

HttpServletRequest 객체를 통한 정보 공유는 동일한 요청에서 실행된 페이지끼리만 이루어지며, 이때는 클라이언트가 요청한 페이지에서 다른 페이지로 이동해야 하는데, 클라이언트가 요청한 페이지가 실행되다가 다른 페이지로 이동하는 것'요청 재지정'이라고 합니다. 즉, 클라이언트로부터의 요청에 대하여 서버에 존재하는 다른 자원으로 요청을 재지정하는 것을 요청 재지정이라고 하는데요. 이때 다른 자원이란, HTML, 이미지, 서블릿 그리고 JSP 등 웹 애플리케이션을 구성하는 어떤 파일이든 대상이 될 수 있습니다. 클라이언트에서는 서버에 보낸 요청을 다른 자원으로 재지정하는 것을 알 수 없습니다.

 

요청 재지정 기능을 제공하는 객체는 다음 2가지가 있습니다.

  • HttpServletResponse
  • RequestDispatcher

 

 

 

HttpServletResponse 요청 재지정

HttpServletResponse 객체에서 제공하는 메소드를 사용하여 요청을 재지정할 때는 요청을 재지정하는 자원이 현재 자원과 동일한 웹 애플리케이션에 속하지 않아도 상관없고, 동일한 서버에 존재하지 않아도 상관없습니다.

 

HttpServletResponse 객체에서 제공하는 요청 재지정 메소드는 다음과 같습니다.

접근자 & 반환형 메소드 기능
public void sendRedirect(String location) location에 설정된 자원으로 요청을 재지원한다.
public String encodeRedirectURL(String url) url에 설정된 URL 문자열에 세션 ID 정보를 추가하여 요청을 재지정한다.

 

sendRedirect() 메소드를 이용하여 다른 서버의 자원으로 이동하는 예제를 작성해보겠습니다. 먼저, WebContent 아래에 site.html 파일을 작성합니다.

 

// site.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>포털 사이트/title>
</head>
<body>
	<form action="portalSite">
		<input type="radio" name="site" value="naver">네이버<br>
		<input type="radio" name="site" value="daum">다음<br>
		<input type="radio" name="site" value="zum">줌<br>
		<input type="radio" name="site" value="google">구글<br>
		<input type="submit" value="이동">
	</form>
</body>
</html>

 

package com.edu.test;

import java.io.*;
import javax.servlet.*;
import javax.servlet.annotation.*;
import javax.servlet.http.*;

@WebServlet("/portalSite")
public class SendRedirectTestServlet extends HttpServlet{

	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		String param = req.getParameter("site");
		if(param.equals("naver")) {
			resp.sendRedirect("http://www.naver.com");
		} else if(param.equals("daum")) {
			resp.sendRedirect("http://www.daum.net");
		} else if(param.equals("zum")) {
			resp.sendRedirect("http://zum.com");
		} else if(param.equals("google")) {
			resp.sendRedirect("http://www.google.com");
		}
		
	}
}

 

이처럼 sendRedirect() 메소드는 다른 페이지로 이동할 수 있는 메소드이며, 현재 서버가 아닌 다른 서버의 자원으로도 이동할 수 있습니다.

 

RequestDispatcher 요청 재지정

RequestDispatcher 객체에서 제공하는 메소드를 사용하여 요청을 재지정할 때는 요청을 재지정하는 자원이 반드시 현재 자원과 동일한 웹 애플리케이션에 있어야만 합니다.

 

RequestDispatcher 객체에서 제공하는 요청 재지정 메소드는 다음과 같습니다.

 

접근자 & 반환형 메소드 기능
public void forward(ServletRequest request, ServletResponse response) 요청을 다른 자원으로 넘긴다.
public void include(ServletRequest request, ServletResponse response) 다른 자원의 처리 결과를 현재 페이지에 포함한다.

 

 

(1) RequestDispatcher 객체 생성

인터페이스인 RequestDispatcher 객체를 생성할 때는 다음과 같이 팩토리 메소드를 사용합니다.

 

  • ServletContext 객체에서 제공하는 메소드

    • RequestDispatcher getNamedDispatcher(String name)
    • RequestDispatcher getRequestDispatcher(String path)

 

  • ServletRequest 객체에서 제공하는 메소드

    • RequestDispatcher getRequestDispatcher(String path)

 

요청을 재지정할 대상에 대한 정보를 path 형식, name 등 어떤 것으로 지정하는가만 다를 뿐 대상을 지정하면서 RequestDispatcher() 메소드에서는 path를 지정할 때 절대 경로뿐만 아니라 상대 경로도 가능하지만, ServletContext 객체의 팩토리 메소드에서는 절대 경로만 지정할 수 있습니다.

 

 

(2) forward() 메소드: forward(ServletRequest request, ServletResponse response)

RequestDispatcher 객체의 forward() 메소드는 클라이언트의 요청으로 생성되는 HttpServletRequest와 HttpServletResponse 객체를 다른 자원에 전달하고 수행 제어를 완전히 넘겨서 다른 자원의 수행 결과를 클라이언트로 응답하도록 하는 기능의 메소드입니다. 다음 그림과 같이 클라이언트로부터의 요청을 다른 자원에 넘겨서 다른 자원으로 요청을 재지정합니다.

 

 

다음은 RequestDispatcher 객체의 forward() 메소드를 활용하는 예제입니다. DispatcherTest1Servlet이라는 이름의 새로운 서블릿을 작성합니다.

 

//DispatcherTest1Servlet.java

package com.edu.test;

import java.io.*;
import javax.servlet.*;
import javax.servlet.annotation.*;
import javax.servlet.http.*;


@WebServlet("/dispatcher")
public class DispatcherTest1Servlet extends HttpServlet{
	
	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		resp.setContentType("text/html;charset=UTF-8");
		PrintWriter out = resp.getWriter();
		out.print("<h3> Dispatcher Test1의 수행결과</h3>");
		
		ServletContext sc = this.getServletContext();
		RequestDispatcher rd = sc.getRequestDispatcher("/dispatcher2");
		rd.forward(req, resp);
		
		out.close();
	}

}

 

//DispatcherTest2Servlet.java
package com.edu.test;

import java.io.*;
import javax.servlet.*;
import javax.servlet.annotation.*;
import javax.servlet.http.*;

@WebServlet("/dispatcher2")
public class DispatcherTest2Servlet extends HttpServlet{
	
	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		resp.setContentType("text/html;charset=UTF-8");
		PrintWriter out = resp.getWriter();
		out.print("<h3> Dispatcher Test2의 수행 결과</h3>");
		out.close();
	}
	
}

 

[실행 결과]

 

 

 

 

 

(3) include() 메소드: include(ServletRequest request, ServletResponse response)

include()는 클라이언트의 요청으로 생성되는 HttpServletRequest와 HttpServletResponse 객체를 다른 자원에 전달하고 수행한 다음, 그 결과를 클라이언트에서 요청한 서블릿 내에 포함하여 클라이언트로 응답하는 기능의 메소드입니다.

 

 

다음은 RequestDispatcher 객체의 include() 메소드를 활용하는 예제입니다. 이전에 작성된 DispatcherTest1Servlet.java 소스에서 rd.forward(req, resp); 부분만 rd.include(req, resp);로 변경합니다.

 

//DispatcherTest1Servlet.java
~생략~
	ServletContext sc = this.getServletContext();
	RequestDispatcher rd = sc.getRequestDispatcher("/dispatcher2");
	rd.include(req, resp);
~생략~

 

 

[실행 결과]

 

 

 

 

(4) Request 단위 정보 공유

RequestDispatcher 객체의 요청을 재지정하는 forward()나 include() 메소드를 이용해 다른 페이지로 이동할 때는 현재 페이지가 사용하는 HttpServletRequest와 HttpServletResponse 객체를 그대로 전달하면서 이동하므로 이전 페이지나 이동한 페이지나 같은 객체를 사용합니다. 그래서 한 번의 요청으로 실행된 페이지끼리 정보를 공유하고자 할 때 HttpServletRequest를 통해 공유할 수 있습니다.

 

다음은 HttpServletRequest를 통해 동일한 요청 페이지 간에 정보를 공유하는 예제입니다. 먼저, bookInput.html를 작성합니다.

//bookInput.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>책 등록</title>
</head>
<body>
<form action="bookReg" method="post">
	책제목: <input type="text" name="title"><br>
	책저자: <input type="text" name="author"><br>
	출판사: <input type="text" name="publisher"><br>
	<input type="submit" value="등록"/>
</form>
</body>
</html>

 

Book이라는 이름의 새로운 일반 자바 소스를 작성합니다. HTML 파일에서 입력한 데이터 값을 저장할 목적으로 만드는 객체입니다. 객체의 멤버변수가 bookInput.html에서 입력받는 값과 일치하는 것을 확인할 수 있습니다.

//Book.java
package com.edu.test;

public class Book {
	private String title;
	private String author;
	private String publisher;
	
	public String getTitle() {
		return title;
	}
	public void setTitle(String title) {
		this.title = title;
	}
	public String getAuthor() {
		return author;
	}
	public void setAuthor(String author) {
		this.author = author;
	}
	public String getPublisher() {
		return publisher;
	}
	public void setPublisher(String publisher) {
		this.publisher = publisher;
	}
}

 

 

BookTest1Servlet이라는 이름의 서블릿 소스를 작성합니다.

//BookTest1Servlet.java
package com.edu.test;

import java.io.*;
import javax.servlet.*;
import javax.servlet.annotation.*;
import javax.servlet.http.*;

@WebServlet("/bookReg")
public class BookTest1Servlet extends HttpServlet{
	
	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		resp.setContentType("text/html;charset=UTF-8");
		PrintWriter out = resp.getWriter();
		
		req.setCharacterEncoding("UTF-8");
		
		String title = req.getParameter("title");
		String author = req.getParameter("author");
		String publisher = req.getParameter("publisher");
		
		Book book = new Book();
		book.setTitle(title);
		book.setAuthor(author);
		book.setPublisher(publisher);
		
		req.setAttribute("book", book);
		
		RequestDispatcher rd = req.getRequestDispatcher("bookOutput");
		rd.forward(req, resp);
		out.close();
	}
}

 

[실행 결과]

 

반응형

댓글