[스프링] 2. 웹 백엔드 프로그래밍 기초 - JSP & redirect & forward & scope

JM·2022년 11월 26일
0
post-thumbnail

JSP(JavaServer Pages)

JSP란?

  • 서블릿을 통해 HTML을 문서를 작성할 수 있지만, print()안에 일일이 넣어야 한다는단점이 존재했다.
  • 이를 해결하기 위해 HTML형식으로 작성할 수 있는 JSP가 등장하였다.
  • JSP는 실제 서블릿 기술을 사용한다.
  • 즉, HTML과 비슷하게 생겼지만, HTML처럼 실행되는 것이 아니라 서블릿으로 봐뀐 이후에 서블릿 작동 방식으로 실행된다. 따라서 Lifecycle 또한 서블릿과 동일하다.

EX)

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>

<%
	int total = 0;
	for(int i = 1; i <= 10; i++){
		total = total + i;
	}
%>

1부터 10까지의 합 : <%=total %>

</body>
</html>

Java코드는 <% %> 안에 집어넣는다. 그리고 <% %>안에 있던 코드들의 값들을 HTML에 포함시켜 전송하기 위해서는 <%=변수명 %>을 사용한다. <%=변수명 %>은 println(변수명)과 동일한 의미이다.


JSP 라이프싸이클

WAS는 웹 브라우저로부터 JSP에 대한 요청을 받게 되면, JSP코드를 서블릿 소스코드로 변환한 후 컴파일하여 실행되게 된다. 서블릿으로 컴파일되어 실행될 때 상황에 따라서 어떤 메소드들이 실행되는지 잘알아야, JSP를 알맞게 작성할 수 있다.JSP파일은 컴파일 시 Servlet코드로 변환된다. 변환된 파일은 아래 경로를 통해 찾을 수 있다.

.metadata -> .plugins -> org.eclipse.wst.server.core -> tmp0 -> work -> Catalina-> localhost -> 프로젝트명 -> org -> apache -> jsp경로에 들어가면 class파일과 java파일을 확인할 수 있다.

java파일

      out.write("\r\n");
      out.write("<!DOCTYPE html>\r\n");
      out.write("<html>\r\n");
      out.write("<head>\r\n");
      out.write("<meta charset=\"UTF-8\">\r\n");
      out.write("<title>Insert title here</title>\r\n");
      out.write("</head>\r\n");
      out.write("<body>\r\n");
      out.write("\r\n");

	int total = 0;
	for(int i = 1; i <= 10; i++){
		total = total + i;
	}

      out.write("\r\n");
      out.write("\r\n");
      out.write("1부터 10까지의 합 : ");
      out.print(total );
      out.write("\r\n");
      out.write("\r\n");
      out.write("</body>\r\n");
      out.write("</html>");

HTML문서의 각 줄을 out.writer()를 통해 변환된 것을 알 수 있다.


sum10.jsp가 실행될 때 벌어지는 일

  • 이클립스 워크스페이스 아래의 .metadata 폴더에 sum10_jsp.java파일이 생성된다.
  • 해당 파일의 "jspService()"메소드 안을 살펴 보면 jsp파일의 내용이 변환되서 들어가있는 것을 확인할 수 있다.
  • sum10_jsp.java는 서블릿 소스로 자동으로 컴파일 되면서 실행되어 그 결과가 브라우저에 보여진다.

JSP의 실행순서

  1. 브라우저가 웹서버에 JSP에 대한 요청 정보를 전달한다.
  2. 브라우저가 요청한 JSP가 최초로 요청했을 경우만
  3. JSP로 작성된 코드가 서블릿 코드로 변환된다. (java 파일 생성)
  4. 서블릿 코드를 컴파일해서 실행가능한 bytecode로 변환한다. (class 파일 생성)
  5. 서블릿 클래스를 로딩하고 인스턴스를 생성한다.
  6. 서블릿이 실행되어 요청을 처리하고 응답 정보를 생성한다.

스크립트 요소의 이해

  • JSP페이지에서는 선언문, 스크립트릿, 표현식 이라는 3가지의 스크립트 요소를 제공한다.
  • 선언문(Declaration) - <%! %> : 전역변수 선언 및 메소드 선언에 사용
  • 스크립트릿(Scriptlet) - <% %> : 프로그래밍 코드 기술에 사용
  • 표현식(Expression) - <%=%> : 화면에 출력할 내용 기술에 사용

스크립트릿

<%
for(int i = 1; i <= 5; i++){
%>
<H<%=i %>> 아름다운 한글 </H<%=i %>>
<%
}
%>

위와 같은 방식을 수행했을 때, for문 안에있는 HTML코드가 반복되어 실행된다.


주석

  • 사용가능한 주석 : HTML 주석, Java 주석, JSP 주석
  • JSP 주석은 JSP에서 Java코드로 변환될 때 주석부분은 변환되지 않는다.
  • Java 주석은 JSP에서 Java코드로 변환될 떄는 함께 변환되지만,Java에서 HTML으로 변환될 때 Java주석부분은 변환되지 않는다.
  • HTML주석은 함께 변환되지만, 브라우저에서는 주석으로 표시되어 화면에 나타나지 않는다.

JSP 내장객체란

  • JSP를 실행하면 서블릿 소스가 생성되고 실행된다.
  • JSP에 입력한 대부분의 코드는 생성되는 서블릿 소스의 _ jspService() 메소드 안에 삽입되는 코드로 생성된다.
  • _ jspService()에 삽입된 코드의 윗 부분에 미리 선언된 객체들이 있는데, 해당 객체들은 jsp에서도 사용가능하다.
  • response, request, application, session, out과 같은 변수를 내장객체라고 한다.
      response.setContentType("text/html; charset=UTF-8");
      pageContext = _jspxFactory.getPageContext(this, request, response,
      			null, true, 8192, true);
      _jspx_page_context = pageContext;
      application = pageContext.getServletContext();
      config = pageContext.getServletConfig();
      session = pageContext.getSession();
      out = pageContext.getOut();
      _jspx_out = out;

내장 객체의 종류

  • request : HTML Form 요소 선택 값과 같은 사용자 입력 정보를 읽어올 때 사용
  • response : 사용자 요청에 대한 응답을 처리할 때 사용
  • pageContext : 현재 JSP 실행에 대한 context 정보를 참조하기 위해 사용
  • session : 클라이언트 세션 정보를 처리하기 위해 사용
  • application : 웹 서버의 어플리케이션 처리와 관련된 정보를 참조하기 위해 사용
  • out : 사용자에게 전달하기 위한 output 스트림을 처리하기 위해 사용
  • config : 현재 JSP에 대한 초기화 환경을 처리하기 위해 사용
  • page : 현재 JSP 페이지에 대한 클래스 정보
  • exception : 예외 처리를 위해 사용



redirect & forward

redirect

  • 리다이렉트는 http프로토콜로 정해진 규칙이다.
  • 서버는 클라이언트로부터 요청을 받은 후, 클라이언트에게 특정 URL로 이동하라고 요청할 수 있다.이를 리다이렉트라고 한다.
  • 서버에서는 클라이언트에게 응답으로 상태코드를 302와 함께 이동할 URL정보를 Location 헤더에 담아전송한다. 클라이언트는 서버로 부터 받은 상태값이 302이면 Location헤더값으로 재요청을 보내게 된다.이때 브라우저의 주소창은 전송받은 URL로 바뀌게 된다.
  • 서블릿이나 jsp는 redirect하기 위해서 HttpServletResponse가 가지고 있는 sendRedirect()메소드를사용한다.
  • 리다이렉트하면 클라이언트가 요청을 2번하게 된다.
  • 처음 요청에 의해 생긴 객체와 리다이렉트 이후 생긴 객체는 서로 다른 객체이다.

EX)

response.sendRedirect("redirect02.jsp");

redirect 동작 설명

https://github.com/JMsuper/boostcourse_web_backend/raw/main/img/redirect%20process.png


forward

https://github.com/JMsuper/boostcourse_web_backend/raw/main/img/forward%20process.png

  1. 웹 브라우저에서 Servlet1에게 요청을 보낸다.
  2. Servlet1은 요청을 처리한 후, 그 결과를 HttpServletRequest에 저장한다.HttpServletRequest 객체는 요청 과정동안 살아있기 때문에 해당 객체에 저장하는 것이다.
  3. Servlet1은 결과과 저장된 HttpServletRequest와 응답을 위한 HttpServletResponse를 같은 웹어플리케이션 안에 있는 Servlet2에게 전송한다.(forward)Servlet2는 HttpServletRequest,Response 객체의 래퍼런스를 모르기 때문에 알려줘야 한다.
  4. Servlet2는 Servlet1으로 부터 받은 HttpServletRequest와 HttpServletResponse를 이용하여요청을 처리한 후 웹 브라우저에게 결과를 전송한다.

EX)

Servlet1.java

	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);
	}

request.setAttribute("dice", diceValue); : request 객체에 "dice"라는 속성값으로 diveValue를 저장한다.이때 diveValue는 Object로 저장된다. 왜냐하면 다양한 type의 데이터가 저장될 수 있기 때문이다.

RequestDispatcher requestDispatcher = request.getRequestDispatcher("/next"); :

파라미터는 forward할 servlet의 경로이다.파라미터 값에 "/"를 가장 앞단에 두면 relative path로 작동한다. 본 servlet이 위치하던 폴더를 기준으로 servlet을 검색할 것이다.RequstDispathcer 클래스는 현재 request에 담긴 정보를 저장하고 있다가 그 다음 페이지에도 해당 정보를 볼 수 있게하는 클래스이다.

requestDispatcher.forward(request, response); : request, response객체를 resquestDispatcher가 가지고 있는 경로의 servlet으로 이동한다.


Servlet2.java

	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>");
		
		// getAttribute는 Object를 리턴하기 때문에 
		// Interger로 형변환해줘야 한다.
		int dice = (Integer)request.getAttribute("dice");
		out.println("dice: " + dice + "<br>");
		for(int i = 0; i < dice; i++) {
			out.print("hello<br>");
		}
		out.println("</body>");
		out.println("</html>");
	}

int dice = (Integer)request.getAttribute("dice"); : request에 저장된 attribute는 기본적으로 Object type이다.따라서 이를 알맞은 type으로 형변환해줘야 한다.


Servlet과 JSP연동

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

EX)

<%
	int v1 = (int)request.getAttribute("v1");
	int v2 = (int)request.getAttribute("v2");
	int result = (int)request.getAttribute("result");
%>
<%=v1 %> + <%=v2 %> = <%=result %>

forward()를 실행하는 Servlet에서의 코드는 서블릿과 서블릿과의 forward()와 동일하다.다만, JSP의 경우 forward()를 받는 서블릿의 코드를 JSP문법에 맞게 작성하면된다.이때 request는 JSP코드가 서블릿코드로 변환되면서 초기화되는 내장객체이기 때문에 사용가능하다.



scope

4가지의 scope

  • Application : 웹 어플리케이션이 시작되고 종료될 때까지 변수가 유지되는 경우 사용
  • Session : 웹 브라우저 별로 변수가 관리되는 경우 사용
  • Request : http요청을 WAS가 받아서 웹 브라우저에게 응답할 때까지 변수가 유지되는 경우 사용
  • Page : 페이지 내에서 지역변수처럼 사용 https://github.com/JMsuper/boostcourse_web_backend/raw/main/img/JSP%20scope.png

Page scope

  • PageContext 추상 클래스를 사용한다.
  • JSP 페이지에서 pageContext 라는 내장 객체로 사용가능 하다.
  • forward가 될 경우 해당 Page scope에 지정된 변수는 사용할 수 없다.
  • 사용방법은 다른 scope들과 동일하다
  • 마치 지역변수처럼 사용된다는 것이 다른 Scope들과 다르다.
  • JSP에서 pageScope에 값을 저장 한 후 해당 값을 EL표기법에서 사용할 때 사용된다.지역 변수처럼 해당 JSP나 서블릿이 실행되는 동안에만 정보를 유지하고자 할 때 사용된다.
  • pageContext는 실제 사용할 일이 많이 없고, JSP에서 서블릿으로 변환될 때 내장 객체 초기화에이용된다.

JSP를 서블릿으로 변환한 코드 중 일부

pageContext = _jspxFactory.getPageContext(this, request, response,
      			null, true, 8192, true);
      _jspx_page_context = pageContext;
      application = pageContext.getServletContext();
      config = pageContext.getServletConfig();
      session = pageContext.getSession();
      out = pageContext.getOut();

request scope

  • http요청을 WAS가 받아서 웹 브라우저에게 응답할 때까지 변수값을 유지하고자 할 경우
  • HttpServletRequest객체를 사용한다.
  • JSP에서는 request내장 변수를 사용한다.
  • 서블릿에서는 HttpServletRequest객체를 사용한다.
  • 값을 저장할 때는 request객체의 setAttribute()메소드를 사용한다.
  • 값을 읽어들일 때는 request객체의 getAttribute()메소드를 사용한다.
  • forward시 값을 유지하고자 사용한다.
  • 앞에서 forward에 대하여 배울 때 forward하기 전에 request객체의 setAttribute()메소드로 값을설정한 후, 서블릿이나 jsp에게 결과를 전달하여 값을 출력하도록 하였는데 이렇게 포워드 되는동안 값이 유지되는 것이 Request scope를 이용했다고 한다.

forward()를 수행하는 서블릿

request.setAttribute("v1", v1);
...
requestDispatcher.forward(request,response);

forward() 당하는 서블릿

int v1 = (int)request.getAttribute("v1");

Session scope

  • 웹 브라우저 별로 변수를 관리하고자 할 경우 사용한다.
  • 웹 브라우저간의 탭간에는 세션정보가 공유되기 때문에, 각각의 탭에서는 같은 세션정보를사용할 수 있다.
  • HttpSession인터페이스를 구현한 객체를 사용한다.
  • JSP에서는 session내장 변수를 사용한다.
  • 서블릿에서는 HttpServletRequest의 getSession()메소드를 이용하여 session객체를 얻는다.
  • 값을 저장할 때는 session 객체의 setAttribute()메소드를 사용한다.
  • 값을 읽어들일 때는 session 객체의 getAttribute()메소드를 사용한다.
  • 장바구니처럼 사용자별로 유지가 되어야 할 정보가 있을 때 사용한다.

Application scope

  • 웹 어플리케이션이 시작되고 종료될 때까지 변수를 사용할 수 있다.
  • ServletContext 인터페이스를 구현한 객체를 사용한다.
  • jsp에서는 application 내장 객체를 이용한다.
  • 서블릿의 경우는 getServletContext()메소드를 이용하여 application 객체를 이용한다.
  • 웹 어플리케이션 하나당 하나의 application객체가 사용된다.
  • 값을 저장할 때는 application 객체의 setAttribute()메소드를 사용한다.
  • 값을 읽어들일 때는 application 객체의 getAttribute()메소드를 사용한다.
  • 모든 클라이언트가 공통으로 사용해야할 값들이 있을 때 사용한다.

Servlet1

    ServletContext application = getServletContext();
		int value = 1;
		application.setAttribute("value", value);

Servlet2

    ServletContext application = getServletContext();
    int value = (int)application.getAttribute("value");
    value++;
    application.setAttribute("value", value);

위에서 application 객체에 집어넣은 value값은 다른 클라이언트에서 접속할 때도 공유되는 값이다.만약, getAttribute(공유자원이름)에서 공유자원이름에 해당하는 것이 없을 경우NullPointerException을 발생시킨다.

profile
블로그 이전 : https://blog.naver.com/tjsqls2067

0개의 댓글