39. JSP의 주요 구성 요소 (3)
- 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