본문 바로가기
Servlet & JSP

Forward, 그리고 Servlet & JSP의 연동

by kmmguumnn 2018. 6. 30.


Forward란?


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

2. Servlet1은 요청을 처리한 후, 그 결과값을 HttpServletRequest에 저장. (Servlet1이 모든 일을 혼자 처리하지 않는다)

3. Servlet1은 결과가 저장된 HttpServletRequest와, 응답을 위한 HttpServletResponse를 같은 웹 어플리케이션 안에 있는 Servlet2에게 넘겨준다 (⇒ forward)

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

물론 여기서 forward를 꼭 Servlet과 Servlet 사이에서만 할 수 있는 것은 아니다! 뒤에서 Servlet과 JSP 사이의 forward도 살펴보자.



redirect와 forward의 차이는?


redirect는 서버가 클라이언트에게 요청을 받아 어떤 일을 처리한 뒤, 클라이언트에게 다시 요청할 곳을 알려주고 클라이언트에 의해 새로운 요청이 발생한다.

반면 forward는 다른 Servlet에게 추가적인 처리를 맡기는 것이다. 클라이언트 입장에서는, Servlet1이 모든 것을 다 처리했는지, 아니면 일부분을 Servlet2에게 위임했는지 여부는 알 필요가 없다. 그래서 forward가 처리된 다음에도 url은 바뀌지 않고 초기 요청한 그대로 유지된다.


클라이언트가 서버에 요청하게 되면, WAS는 HttpServletRequest 객체와 HttpServletResponse 객체를 만든다. 

Redirect는 요청이 여러 번 왔다갔다 하므로, 한번 요청할 때마다 새로운 Request와 Response 객체가 만들어진다.

반면 Forward는 새로운 요청이 추가되는 것이 아니므로, 각각의 객체가 한번만 만들어진다. 즉, 요청이 들어와서 응답을 할 때까지 Request와 Response 객체는 계속 유지되고 있는 상태다. 


결국 가장 큰 차이점은, "Request가 하나인지, 서로 다른 여러가지인지"가 다르다는 것이다.



그럼 이제 예제 코드를 살펴 보자.


    @WebServlet("/front")
    public class FrontServlet extends HttpServlet {
        private static final long serialVersionUID = 1L;

        public FrontServlet() {
            super();
        }
        
        protected void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
            // 주사위 값 랜덤
            int diceValue = (int) (Math.random() * 6) + 1;

            // request에 diceValue값을 맡긴다(저장)
            // 그래야만 forward 대상이 되는 servlet에서도 diceValue값을 사용할 수 있다
            request.setAttribute("dice", diceValue);

            // NextServlet("/next")에 request와 response를 forward (같은 웹애플리케이션 내의 servlet에게만 가능)
            RequestDispatcher requestDispatcher = request.getRequestDispatcher("/next");
            requestDispatcher.forward(request, response);   // request, response 객체를 NextServlet에게 넘겨준다
        }
    }
    


FrontServlet.java의 모습이다. 이제 NextServlet.java로 forward하는데, RequestDispatcher.forward를 활용한다.




    @WebServlet("/next")
    public class NextServlet extends HttpServlet {
        private static final long serialVersionUID = 1L;

        public NextServlet() {
            super();
        }

        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);
            
            for (int i = 0; i < dice; i++) {
                out.print("<br>hello");
            }
            out.println("</body>");
            out.println("</html>");
        }
    }



NextServlet.java에서는 FrontServlet.java로부터 request와 response 객체를 전달 받고, 받은 데이터를 활용해 출력을 진행한다.

request.getAttribute()는 Object 형이 반환되므로, 적절하게 형변환도 해준다.








Servlet과 JSP의 연동


Servlet은 프로그램 로직을 구현하기에는 편리하지만, HTML 태그를 출력하기엔 불편하다.

반면 JSP는 프로그램 로직을 구현하기에는 좀 불편하지만, HTML 태그를 출력하기엔 편리하다.

즉 서로의 장단점이 완전히 반대다.


이러한 점을 forward를 이용해 개선할 수 있다.

프로그램 로직이 필요한 부분은 Servlet에서 수행하고, 그 결과를 HTML 페이지를 구현한 JSP로 forwarding하면 된다. (Servlet과 JSP의 연동)

  • Servlet은 프로그램 로직이 수행되기에 유리하다. IDE 등에서 지원을 좀 더 잘해준다.
  • JSP는 결과를 출력하기에 Servlet보다 유리하다. 필요한 HTML문을 그냥 입력하면 됨.
  • 프로그램 로직 수행은 Servlet에서, 결과 출력은 JSP에서 하는 것이 유리하다.
  • Servlet과 JSP의 장단점을 해결하기 위해서 Servlet에서 프로그램 로직이 수행되고, 그 결과를 JSP에게 포워딩하는 방법이 사용되게 되었다. 이를 Servlet과 JSP의 연동이라고 한다.

위의 그림대로 예제 코드를 만들어 보자.


    @WebServlet("/logic")
    public class LogicServlet extends HttpServlet {
        private static final long serialVersionUID = 1L;

        public LogicServlet() {
            super();
        }

        protected void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
            int v1 = (int) (Math.random() * 100) + 1;
            int v2 = (int) (Math.random() * 100) + 1;
            int result = v1 + v2;
            
            // request 객체에 v1, v2, result를 담아준다. 향후 포워딩 대상(result.jsp)에서 사용한다.
            request.setAttribute("v1", v1);
            request.setAttribute("v2", v2);
            request.setAttribute("result", result);
            
            // "/result.jsp"에 request, response 객체를 Forward
            RequestDispatcher rd = request.getRequestDispatcher("/result.jsp");
            rd.forward(request, response);
        }
    }


먼저 LogicServlet.java이다. 클라이언트는 LogicServlet에게 요청을 보낸다. 앞서 보았던 예제와 마찬가지 방식으로, request 객체에 변수들을 담아주고, 이번에는 "/result.jsp"로 forward한다.




<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<%
int v1 = (int)request.getAttribute("v1");
int v2 = (int)request.getAttribute("v2");
int result = (int)request.getAttribute("result");
%>
<%= v1 %> + <%= v2 %> = <%= result %>
</body>
</html>


result.jsp에서는 request 객체와 response 객체를 받을 것이고, 받은 데이터를 Scriptlet 안에서 변수에 저장한 뒤 표현식으로 출력하고 있다.

마찬가지로 request.getAttribute()는 Object 형이 반환되므로, 형변환을 해줘야 한다.




<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<!-- <%
int v1 = (int)request.getAttribute("v1");
int v2 = (int)request.getAttribute("v2");
int result = (int)request.getAttribute("result");
%>
<%= v1 %> + <%= v2 %> = <%= result %> -->
${v1 } + ${v2 } = ${result }
</body>
</html>


출력하는 방법에는 'EL(Expression Language) 표기법'이라는 더 간단한 것이 있다. ${변수}와 같이 써주기만 하면 바로 출력된다. JSP에서는 Java 코드를 최대한 줄이는 것이 좋은데, 이를 위해 EL 표기법을 사용하는 것이다. 마치 Javascript(ES6)의 template literal과 유사하게 생겼다.

EL 표기법에 대해서는 여기에서 더 자세히 살펴본다.



'Servlet & JSP' 카테고리의 다른 글

EL(Expression Language)과 JSTL(JSP Standard Tag Library)  (1) 2018.07.01
Servlet & JSP의 4가지 Scope  (0) 2018.07.01
Redirect  (0) 2018.06.29
JSP 기초  (0) 2018.06.29
Servlet 기초  (0) 2018.06.29

댓글