본문 바로가기
Backend/Servlet & JSP

[Servlet & JSP] 서블릿 forward와 redirect

by Forsaken Developer 2023. 5. 23.
728x90
728x90

[Servlet & JSP] 서블릿 forward와 redirect

서블릿의 역할은 요청 받기, 비즈니스 로직 처리, 요청에 대한 응답이다.

하나의 서블릿에서 이 모든 역할을 처리하려고 할 때 문제가  발생할 수 있다.

각각의 역할에 종속성이 생기게 되어 하나의 서블릿을 수정하여도 연관된 서블릿에 영향을 주게 되며 규모가 커지면서 각각의 서블릿이 감당하기에 부담이 된다.

요청을 받는 역할은 수행하고 비즈니스 로직에 대한 처리는 서비스를 호출하는 방식으로 해결하며 응답에 대한 처리는 별도의 서블릿으로 관리한다.

그렇다면 서로 다른 서블릿 간 데이터를 전달할 수 있는 방법이 필요하고 forward와 redirect 방식이 있다.

forward

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Forward</title>
</head>
<body>
    <form action="forward" method="post">
        <label>아이디</label>
        <input type="text" name="userId">
        <br>
        <label>비밀번호</label>
        <input type="password" name="password">
        <br>
        <input type="submit" value="로그인">
        
    </form>
</body>
</html>

먼저 post 요청을 위한 HTML 파일을 작성한다.

@WebServlet("/forward")
public class ReceiveServlet extends HttpServlet {
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
         request.setCharacterEncoding("UTF-8");
         String userId = request.getParameter("userId");
         String password = request.getParameter("password");
         String shownUserId = userId + "님";
	     
         //new LoginSuccessServlet().doPost(request, response);
	     
         request.setAttribute("shownUserId", shownUserId);
         
         RequestDispatcher rd = request.getRequestDispatcher("print");
         rd.forward(request, response);
	}
}

요청을 받는 역할을 수행하는 서블릿을 작성한다.

사용자로 부터 입력받은 id와 password는 getParameter로 받아올 수 있다.

이때 데이터를 응답과 관련된 서블릿으로 전달하기 위해서 서블릿 메서드를 직접 생성하여 request와 response를 전달할 수 있다.

하지만 두 서블릿 간의 의존관계가 생기기때문에 서블릿을 나누는 의미가 희미해진다.

대신 다른 서블릿에 매핑되어있는 url로 요청을 위임할 수 있는데 이러한 방식이 forward이다.

RequestDispatcher 객체는 요청에 방향 정보를 가질 수 있는 객체로 전달한 url로 request와 response를 함께 전달한다.

요청으로 부터 전달 받은 데이터가 아닌 가공된 데이터를 전달 하려고 한다면 request의 parameter를 통해서 전달 할 수 없다.

이럴 때 사용할 수 있는 request의 별도의 공간이 Attribute이다. 

setAttribute를 통해서 전달하려는 값을 key(String), value(Object) 형태로 전달하고 getAttribute를 통해서 전달 받을 수 있다.

@WebServlet("/print")
public class LoginSuccessServlet extends HttpServlet {
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
	    
		String shownUserId = (String) request.getAttribute("shownUserId");
		
		StringBuilder responseText = new StringBuilder();
		responseText.append("<!doctype html>\n")
		            .append("<html>\n")
		            .append("<head></head>\n")
		            .append("<body>\n")
		            .append("환영합니다. " + shownUserId+"\n")
		            .append("</body>\n")
		            .append("</html>\n");
		
		response.setContentType("text/html;charset=UTF-8");
		PrintWriter out = response.getWriter();
		out.print(responseText);
		out.flush();
		out.close();
	}
}

페이지 응답에 관련된 코드를 별도의 서블릿으로 작성한다.

getAttribute에 key를 전달하여 value를 전달 받을 수 있는데 value는 object 타입이기때문에 사용하려는 타입으로 다운캐스팅 하여 사용한다.

전달한 request객체의 데이터의 값은 양쪽 모두 같지만 request객체의 hash code를 출력해보면 서로 다른 request 객체이다.

객체를 직접 생성하여 request를 전달하게 되면 이 때 request 객체는 동일한 request객체이다.

이 request를 한 곳에서 조작하게 되면 또 다른 곳에서 문제가 발생할 수 있기 때문에 새롭게 request를 생성하고 깊은 복사 하여 RequestDispatcher를 통해서  호출한다.

forward는 요청을 위임하기만 하기때문에 요청에 대한 응답은 응답 역할을 하는 서블릿을 통해서 가능하다.

따라서 여러번 요청을 하더라도 요청에 대한 경로와 값이 동일하다.

만약 요청을 받은 서블릿이 서비스를 호출하여 데이터베이스에 데이터를 저장하는 상황이라면 새로 고침을 해서 계속 요청 할 경우 매번 데이터가 저장되는 상황이 발생한다.

forward방식으로는 데이터의 입력, 수정, 삭제에는 적절하지 않다.

redirect

redirect 방식은 요청을 하게 되면 요청에 대한 응답을 바로 하고 강제로 다음 요청 경로로 요청하도록 하는 방식이다.

 redirect를 사용하면 데이터베이스에 데이터 저장은 한 번의 요청만 수행하고 계속 요청할 경우 redirect된 서블릿에서만  계속 응답 하기 때문에 매번 데이터베이스에 접근하지 않는다.

redirect는 두 가지 방식이 있다.

@WebServlet("/othercite")
public class OtherRedirectServlet extends HttpServlet {
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
	    response.sendRedirect("https://www.naver.com");
	}
}

첫 번째로는 다른 사이트로의 redirect이다.

response객체의 sendRedirect 메소드에 url을 전달하면 사용자의 url을 강제로 변경한다.

그 이후 새로고침으로 다시 요청하면 처음 요청 주소부터 요청하지 않고 redirect된 주소로 요청한다.

@WebServlet("/otherservlet")
public class OtherRedirectServlet extends HttpServlet {
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		response.sendRedirect("redirect?key=value");
	}
}

두 번째로는 다른 서블릿으로의 redirect이다.

response의 sendRedirect 메소드로 서블릿의 매핑 url을 전달하여 redirect를 수행할 수 있다.

redirect의 request는 새로운 request를 전달하기 때문에 attribute를 통해서 값을 전달 할 수 없는데 이때 query string parameter를 통해서 전달 할 수 있다.

redirect를 위해서 또 다른 서블릿을 작성한다.

@WebServlet("/redirect")
public class RedirectServlet extends HttpServlet {
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String value = request.getParameter("key");
        System.out.println(value);
        System.out.println("redirect 성공");
	}
}

 

728x90
반응형

댓글