교재 실습/자바 웹 개발 워크북

39. JSP의 주요 구성 요소 (3)

Jint 2022. 2. 5. 19:45

- JSP 내장 객체

JSP 페이지에서 스크립트릿 <%  %>이나 표현식 <%=  %>을 작성할 때 별도의 선언 없이 사용하는 자바 객체가 있다. 이런 객체를 JSP 내장 객체(Implicit Objects)라 한다.

<%
String v1 = "";
String v2 = "";
String result = "";
String[] selected = {"", "", "", ""};

//값이 있을 때만 꺼낸다.
if (request.getParameter("v1") != null) {
	v1 = request.getParameter("v1");
	v2 = request.getParameter("v2");
	String op = request.getParameter("op");
	
	result = calculate(
				Integer.parseInt(v1), 
				Integer.parseInt(v2), 
				op);
	...
}
%>

Calculator.jsp에 작성된 스크립트릿 태그의 일부 내용이다. request 객체가 바로 내장 객체에 해당한다. JSP 기술 사양서에는 스크립트릿이나 표현식에서 JSP 내장 객체의 사용을 보장한다고 되어 있으므로 객체를 선언하지 않고 바로 사용할 수 있다. 이것이 가능한 이유를 JSP 엔진이 만든 서블릿 파일의 _jspService()에 선언된 변수들을 확인한다.

 

C:\javaide\workspace\.metadata\.plugins\org.eclipse.wst.server.core\tmp0\work\Catalina\localhost\web05\org\apache\jsp\calc

위 경로의 Calculator_jsp.java 파일의 _jspService()를 살펴본다.

//매개 변수의 내장 객체 request, response
public void _jspService(final javax.servlet.http.HttpServletRequest request, final javax.servlet.http.HttpServletResponse response) throws java.io.IOException, javax.servlet.ServletException {

    final java.lang.String _jspx_method = request.getMethod();
    if (!"GET".equals(_jspx_method) && !"POST".equals(_jspx_method) && !"HEAD".equals(_jspx_method) && !javax.servlet.DispatcherType.ERROR.equals(request.getDispatcherType())) {
      response.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, "JSP들은 오직 GET, POST 또는 HEAD 메소드만을 허용합니다. Jasper는 OPTIONS 메소드 또한 허용합니다.");
      return;
    }

    //내장 객체
    final javax.servlet.jsp.PageContext pageContext;
    javax.servlet.http.HttpSession session = null;
    final javax.servlet.ServletContext application;
    final javax.servlet.ServletConfig config;
    javax.servlet.jsp.JspWriter out = null;
    final java.lang.Object page = this;
    javax.servlet.jsp.JspWriter _jspx_out = null;
    javax.servlet.jsp.PageContext _jspx_page_context = null;


    try {
      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;
	...
}

_jspService()는 javax.servlet.jsp.HttpJspPage 인터페이스에 선언된 메서드이므로 JSP 기술 사양서에는 JSP 페이지로 서블릿을 만들 때 반드시 이 인터페이스를 구현하도록 정의하고 있다. 또한 JSP 기술 사양서는 JSP 페이지 작성자가 별도 선언 없이 즉시 이용할 수 있는 9개 객체를 정의하고 있다. _jspService()에 선언된 request, response, pageContext, session, application, config, out, page, exception 객체가 이에 해당한다. exception은 JSP 페이지가 예외처리 페이지로 선언된 경우에만 존재하기 때문에 위 코드에선 보이지 않는다. 스크립트릿 <%  %>과 표현식 <%=  %>에서 작성한 자바 코드는 _jspService()로 복사될 때 JSP 내장 객체를 선언한 문장 뒤에 놓이기 때문에 별도 선언 없이 스크립트릿과 표현식에서 JSP 내장 객체를 사용할 수 있다.

 

- JSP 전용 태그 : 선언문

JSP 선언문(Declarations) <%! 멤버 변수 및 메서드 선언 %>은 서블릿 클래스의 멤버(변수나 메서드)를 선언할 때 사용하는 태그다. JSP 페이지에서 선언문 <%!  %>을 작성하는 위치는 위, 아래, 가운데 어디든 상관없는데 _jspService() 안에 복사되지 않고 밖의 클래스 블록 안에 복사되기 때문이다.

<%! 
private String calculate(int a, int b, String op) {
	int r = 0;
	
	if ("+".equals(op)) {
		r = a + b;	
	} else if ("-".equals(op)) {
		r = a - b;
	} else if ("*".equals(op)) {
		r = a * b;
	} else if ("/".equals(op)) {
		r = a / b;
	}
	
	return Integer.toString(r);
}
%>

Calculator.jsp에 작성된 계산을 수행하는 calculate()를 <%!  %>에 작성하였다. calculate()는 클라이언트가 보낸 매개변수 값을 계산하여 그 결과를 문자열로 바꾸어 반환한다.

 

선언문 태그에 작성한 자바 코드가 서블릿 파일에 어떻게 되었는지 확인하기 위해 Calculator_jsp.java 파일의 calculate()가 정의된 부분을 살펴본다.

public final class Calculator_jsp extends org.apache.jasper.runtime.HttpJspBase implements org.apache.jasper.runtime.JspSourceDependent, org.apache.jasper.runtime.JspSourceImports {

    private String calculate(int a, int b, String op) {
        int r = 0;

        if ("+".equals(op)) {
            r = a + b;	
        } else if ("-".equals(op)) {
            r = a - b;
        } else if ("*".equals(op)) {
            r = a * b;
        } else if ("/".equals(op)) {
            r = a / b;
        }

        return Integer.toString(r);
    }
    
    ...
}

선언문 태그에 작성한 자바 코드가 클래스 블록 안으로 그대로 복사된 것을 확인할 수 있다.

 

- JSP 전용 태그 : 표현식

표현식(Expressions) 태그 <%= 결과를 반환하는 자바 표현식 %>는 문자열을 출력할 때 사용한다. 따라서 표현식 <%=  %> 안에는 결과를 반환하는 자바 코드가 와야 한다. 표현식도 스크립트릿과 같이 _jspService() 안에 순서대로 복사된다. 표현식 안의 자바 코드는 출력문으로 만들어진다.

<h2>JSP 계산기</h2>
<form action="Calculator.jsp" method="get">
	<input type="text" name="v1" size="4" value="<%=v1%>"> 
	<select name="op">
		<option value="+" <%=selected[0]%>>+</option>
		<option value="-" <%=selected[1]%>>-</option>
		<option value="*" <%=selected[2]%>>*</option>
		<option value="/" <%=selected[3]%>>/</option>
	</select> 
	<input type="text" name="v2" size="4" value="<%=v2%>"> 
	<input type="submit" value="=">
	<input type="text" size="8" value="<%=result%>"><br>
</form>

Calculator.jsp에 작성된 계산 요청이 들어 왔을 때 입력 항목에 그 값을 출력하기 위한 JSP 표현식을 사용한 부분이다. 사용자가 입력한 값이 다시 입력상자에 출력되도록 input태그에 value 속성을 추가하였다. value 속성의 값은 표현식 <%=  %> 태그를 사용하여 출력한다. 사용자가 계산할 때 선택한 연산자를 결과 화면에서도 그대로 선택된 상태로 만들고자 selected[] 배열을 사용했다. 계산 요청이 들어오면 op 연산자의 값이 무엇이냐에 따라 selected[] 배열에서 그 연산자에 해당하는 항목을 찾아 'selected' 문자열을 넣는다. 예시로 op 매개변수의 값이 '*'이면 selected[2] 항목에 'selected' 문자열이 들어간다.

 

표현식 태그에 작성한 자바 코드가 서블릿 파일에 어떻게 되었는지 확인하기 위해 Calculator_jsp.java 파일의 _jspService()를 살펴본다.

public void _jspService(final javax.servlet.http.HttpServletRequest request, final javax.servlet.http.HttpServletResponse response) throws java.io.IOException, javax.servlet.ServletException {
      ...
      out.write("<h2>JSP 계산기</h2>\n");
      out.write("<form action=\"Calculator.jsp\" method=\"get\">\n");
      out.write("	<input type=\"text\" name=\"v1\" size=\"4\" value=\"");
      out.print(v1);
      out.write("\"> \n");
      out.write("	<select name=\"op\">\n");
      out.write("		<option value=\"+\" ");
      out.print(selected[0]);
      out.write(">+</option>\n");
      out.write("		<option value=\"-\" ");
      out.print(selected[1]);
      out.write(">-</option>\n");
      out.write("		<option value=\"*\" ");
      out.print(selected[2]);
      out.write(">*</option>\n");
      out.write("		<option value=\"/\" ");
      out.print(selected[3]);
      out.write(">/</option>\n");
      out.write("	</select> \n");
      out.write("	<input type=\"text\" name=\"v2\" size=\"4\" value=\"");
      out.print(v2);
      out.write("\"> \n");
      out.write("	<input type=\"submit\" value=\"=\">\n");
      out.write("	<input type=\"text\" size=\"8\" value=\"");
      out.print(result);
      out.write("\"><br>\n");
      out.write("</form> \n");
      ...
}

서블릿 소스를 보면 JSP 표현식 안에 있던 자바 코드가 out.print() 출력의 인자값(argument)으로 복사되었다. 즉 JSP 엔진은 표현식 태그에 작성한 자바 코드를 출력문의 인자값으로 복사한다. 출력문을 만들 때 out.print()만 사용하지 않고 out.write()를 사용하기도 하는데 JSP 엔진에 따라 만들어지는 자바 코드가 다를 수 있다. 현재 실습하며 사용하는 서블릿 컨테이너는 톰캣 서버이고, 톰캣 서버에서는 앞의 소스와 같이 JSP 표현식에 대해 out.print()를 만든다. 표현식 안에 어떤 자바 코드를 넣을 수 있는지에 대한 고민은 out.print()의 인자값으로 넣을 수 있는 자바 코드인가를 따져 보면 해결된다.

 

참고도서 : https://freelec.co.kr/book/1674/

 

[열혈강의] 자바 웹 개발 워크북

[열혈강의] 자바 웹 개발 워크북

freelec.co.kr