daniel7481의 개발일지

[웹 프로그래밍(풀스택)] redirect&forward-BE 본문

Naver Boostcourse

[웹 프로그래밍(풀스택)] redirect&forward-BE

daniel7481 2022. 2. 9. 16:26
반응형

1. 리다이렉트(redirect)

- http 프로토콜로 정해진 규칙이다

- 서버는 클라로부터 요청을 받고, 클라에게 특정 url로 이동하라고 요청할 수 있다. 이를 리다이렉트라고 한다.

- 서버에서는 클라에게 응답으로 상태 코드 302와 함꼐 이동할 url정보를 Location Header에 담아 전송한다. 클라는 받은 상태값이 302면 Location 헤더값으로 재요청을 보내게 된다. 이 때 브라우저의 주소창은 전송받은 URL로 바뀌게 된다.

- 서블릿이나 jsp는 redirect하기 위해서 HttpServletResponse가 가지고 있는 sendRedirect()메소드를 사용한다.

이제 실습으로 redirect01.jsp가 redirect02.jsp로 리다이렉트하는 로직이 실행되게 해보자

먼저 redirect01.jsp에서 다른 것은 필요없고 response.sendRedirect("redirect02.jsp")를 입력하자. 그 다음 redirect02.jsp를 만들어준 후 아무거나 적어준 후 redirect01.jsp를 실행해보자. 그러면 눈 깜짝할 사이에 redirect02.jsp로 이동한 것을 알 수 있다. redirect02.jsp를 실행한 것 같지만 브라우저에 검사 안에 네트워크를 들어가보면 redirect01.jsp로 이동했다가, 상태값 302를 받고 redirect02.jsp로 이동한 것을 알 수 있다. 

[출처] Naver Boostcourse

위 그림을 보면 이해가 쉽다. 먼저 우리는 redirect01.jsp를 실행함으로써 tomcat에게 redirect01.jsp를 요청하였고, WAS가 이를 받아들이고 상태값 302를 읽어들인 후 redirect02로 리다이렉트를 요청하였다. 여기서 Location 헤더값은 redirect02.jsp다. 웹 브라우저는 WAS의 리다이렉트 요청을 받고 다시 redirect02.jsp를 요청하였고, WAS는 이제 redirect02.jsp를 화면에 띄워준 것이다. 여기서 브라우저가 요청을 두 번 들어간다는 것을 기억하자. 처음 들어갔던 요청, 응답 객체와 두 번째 들어간 요청, 응답 객체는 다른 것이다.

2. forward

[출처] Naver Boostcourse

위 그림을 보면서 forward를 이해해보자. 크게 보면 클라가 Servlet1에게 요청을 보내고, Servlet1은 모든 요청을 다 처리하지 않고 나머지 부분을 다른 서블릿에게 넘겨준다. 그 다음 Servlet2가 나머지 일을 해내고 클라에게 응답을 보내는 것이 forward이다. redirect와 forward는 엄연히 다르다. redirect는 먼저 클라가 서버에게 요청을 하고 서버가 클라에게 새롭게 요청할 곳을 알려주고, 클라는 다시 요청을 하게 된다. redirect 결과는 실행 후에 url이 바뀌게 된다. forward는 요청에 대해 혼자 처리하는 것이 아니라 다른 누군가에게 맡기는 것이다. 이 때 클라는 Servlet1이 다 처리했는지 누군가에게 부탁했는지 알 필요가 없다. 그래서 url이 바뀌지 않는다. 클라가 서버에게 요청을 보내면 request와 response 객체가 생기는데, forward 같은 경우에는 response, request 객체가 한번만 생성된다. redirect 객체는 앞에서 설명했듯이 두 번 생성하게 된다. 요청이 하나인지 서로 다른 두 개인지가 정말 큰 차이라고 한다. 

1. 웹 브라우저에서 Servlet1에게 요청을 보냄. 

2. Servlet1은 요청을 처리 후 결과를 HttpServletRequest 객체에 저장한다. 이렇게 하는 이유는 Servlet1이 실행한 결과를 Servlet2에게 넘겨줘야 하는데, 지역변수로 선언된 결과를 Servlet2에게는 넘겨 줄 수 없기 때문에, request, response 객체는 이 모든 과정이 끝나기 전까지 사라지지 않기 때문에 이 결과를 HttpServletRequest 객체에 넣어주는 것이다.

3. Servlet1은 결과가 저장된 HttpServletRequest와 응답을 위한 HttpServletResponse를 같은 웹 에플리케이션 안에 있는 Servlet2에게 전송한다(이를 forward라고 한다).

4. Servlet2는 받은 HttpServletRequest와 HttpServletResponse를 이용하여 요청을 처리한 후 웹 브라우저에게 결과를 전송한다. 

실습으로 Servlet1에서 랜덤으로 주사위 숫자를 받고, Servlet2에서 주사위 눈금을 출력해보자

먼저 Servlet1, Servlet2이란 서블릿 두 개를 생성하자. doGet doPost는 오버라이딩할 필요 없고 service만 해주자. 서블릿에서 요청에 대한 모든 추상적인 개념으로 HttpServletRequest가 있고, 응답으로 HttpServletResponse가 있다는 것을 기억하면서 들어가보자

	protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		int diceValue = (int)(Math.random()*6)+1;
		request.setAttribute("dice", diceValue);
		RequestDispatcher requestDispatcher = request.getRequestDispatcher("/next");
		requestDispatcher.forward(request, response);
	}

먼저 주사위 눈금을 랜덤으로 받아야 하니 Math.radom()을 받아주고, 정수로 형변환해준 후 1~6을 위해 *6+1을 해준다. 중요한 부분은 request.setAttribute인데, 이 부분이 바로 HttpServletRequest 객체에 저장해주는 메서드이다. 첫번째 패러미터는 강사님 비유를 빌리자면 세탁소에 옷을 맡길 때 맡기는 이름이다. 예로들어 daniel으로 맡겨주세요라고 할 때 daniel이다. 나중에 사용할때도 이 이름을 사용하면 된다. 두 번째 패러미터가 넣어줄 값이다. 우리는 주사위 눈금 변수를 diceValue로 했기에 넣어준다. 그 다음에 사용할 클라스가 RequestDispatcher인데, 이는 우리가 request 객체를 보낼 위치다. 나 같은 경우에는 두 번째 서블릿의 url mapping을 next로 해줄 것인데, 여기서 중요한 점은 forward를 해줄 때에는 반드시 앞에 /을 넣어줘야 한다는 것이다. 또한 같은 웹 애플리케이션 안에 있는 서블릿만 사용 가능하다. 맨 마지막에 forward를 해준다는 의미인 requestDispatcher.forward(request, response)로 응답 요청 두 개 다 보내준다.

protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		response.setContentType("text/html");
		PrintWriter out = response.getWriter();
		out.println("<html>");
		out.println("<head><title>form</title></head>");
		out.println("<body>");
		
		int dice = (Integer)request.getAttribute("dice");
		out.println("dice: " + dice);
		out.println("</body>");
		out.println("</html>");
	}

이제 보냈으면 받을 서블릿을 만들어야 한다. nextServlet.java를 생성해주고, 서블릿을 생성할때 항상 해주는 setContentType, out 객체 선언을 해준다. 그 다음 기본적인 html 태그들을 달아주고 이제 앞에서 보내주었던 diceValue를 받아야하는데 여기서 request.getAttribute을 사용한다. 앞에서 빼먹은 부분이 있는데, 우리가 forward로 변수를 보낼 때 변수의 형(type)은 Object이다. 이것이 문자열인지 정수인지 확실하지 않기 때문에 Object로 보낸다고 한다. 그래서 받아올 때 앞에 Integer로 형변환을 해준다. 

이제 frontServlet을 서버에서 실행시켜보자. 제대로 출력되는 것을 알 수 있다. 만약 nextServlet을 실행시키면 아무것도 출력이 되지 않는 것을 알 수 있다. 여기서 봐야 할 것은 url이다. 마지막에 실행된 것은 nextServlet이지만, 실제 url은 변화없이 frontServlet이다. 이 같은 점이 redirect와 forward의 가장 큰 차이점이다. 

3. servlet & jsp 연동

- Servlet은 프로그램 로직이 수행되기 유리하다. 서블릿 자체가 자바 파일이기 때문에 비교적 수월하다.

- JSP는 결과를 출력하기가 Servlet보다 유리하다. 필요한 html문을 그냥 입력하면 되기 때문이다.

- 위 같은 이유로 로직 수행은 Servlet에서, 결과 출력은 JSP에서 하는 것이 유리하다.

- 이러한 장단점을 해결하기 위해 Servlet에서 프로그램 로직이 수행되고, 그 결과를 JSP에게 포워딩하는 방법이 사용되게 되는데, 이를 Servlet과 JSP 연동이라고 한다.

실습을 따라하다 보면 위 방법과 정확히 똑같은데, 다른 점 하나는 넘겨줄 때 서블릿의 url mapping이 아닌, WebContent 밑에 있는 jsp 이름으로 해줘야 한다는 것이다. 만약  WebContent 안의 다른 디렉토리에 있으면 /dir/result.jsp로 해주면 된다. 위 방법과 거의 동일함으로 코드는 따로 첨부하지 않겠다.

사실 여기 안에서 jsp에 출력하는 부분은 백보다는 프론트엔드 부분이다. 그러나 이러한 프론트엔드에서 자바 언어가 많아지면 디자이너 입장에서 곤란할 수 있으므로 EL이나 JSTL 같은 것이 생겨났다. <%= %>을 사용하는 것이 아닌 ${변수명}으로 우리가 request로 보냈던 변수를 바로 사용할 수 있다고 한다. 

	<%
	int v1 = (int)request.getAttribute("v1");
	int v2 = (int)request.getAttribute("v2");
	int result = (int)request.getAttribute("result");
	%>
	<%=v1%> + <%=v2 %> = <%=result %>입니다.
    <--위는 아래와 같은 결과를 출력한다.. -->
    ${v1} + ${v2} = ${result}

 

[출처] Naver Boostcourse

서블릿에서 서블릿으로 forward 해주는 과정이랑 크게 다르지 않다. 다른 점 하나는 서블릿에서 로직 부분을 실행한 후 결과를 jsp에서 받은 후에 출력했다는 점 뿐이다.

반응형