posted by 희정냥★ 2007. 3. 16. 08:11

servlet.jar , servlet-api.jar 파일을,시스템의 jre폴더의 lib/ext 안에 복사후 사용.
혹은 웹서버 lib폴더(TOMCAT_HOME/common/lib)에 넣고 사용.

* local의 기본 정보(IP, Name, Port)를 보여줌(local이라 하면 일반적으로 서버를 의미)
Local IP : =request.getLocalAddr()
Local Name : =request.getLocalName()
Local Port : =request.getLocalPort()

* 클라이언트의 정보(IP, Host, Port)
Remote IP : <%=request.getRemoteAddr()%>
Remote Host : <%=request.getRemoteHost()%>
Remote Port : =request.getRemotePort()

* 서버 이름, 포트(일반적으로 local 기본정보와 동일)
Server Name : <%=request.getServerName()%>
Server Port : <%=request.getServerPort()%>

* 지역 정보(대부분 한국을 의미하는 ko가 나옴)
Locale : <%=request.getLocale()%>

* 사용하는 프로토콜("프로토콜/메이저버전.마이너버전" 의 형태)
Protocol : <%=request.getProtocol()%>
http, https, ftp와 같은 것을 의미.
Scheme : <%=request.getScheme()%>

* https와 같은 보안 채널의 사용 여부(true/false 값으로 되어 있음)
Secure Channel : <%=request.isSecure()%>

* 요청에 대한 URI, URL, 컨텍스트 경로, 서블릿 경로, GET/POST등의 메소드를 나타냄
Request's URI : <%=request.getRequestURI()%>
Request's URL : <%=request.getRequestURL()%>

Context Path : <%=request.getContextPath()%>
Servlet Path : <%=request.getServletPath()%>
Method : <%=request.getMethod()%>

* 세션 ID에 대한 정보들
Session ID : <%=request.getRequestedSessionId()%>
Session ID from Cookie : <%=request.isRequestedSessionIdFromCookie()%>
Session ID from URL : <%=request.isRequestedSessionIdFromURL()%>
Session ID is still valid : <%=request.isRequestedSessionIdValid()%>

* Header 정보를 보는 방법
<%
 Enumeration eHeader = request.getHeaderNames();
 while (eHeader.hasMoreElements()) {
 String hName = (String)eHeader.nextElement();
 String hValue = request.getHeader(hName);

 out.println(hName + " : " + hValue + "<br>");
 }
%>

* Request 객체를 통해서 쿠키 정보를 보는 방식
<%
 Cookie cookies[] = request.getCookies();
 for (int i=0; i < cookies.length; i++) {
  String name = cookies[i].getName();
  String value = cookies[i].getValue();

  out.println(name + " : " + value + "<br>");
 }
%>

* HTML 폼을 통해 넘어온 데이터를 받는 부분
<%
 Enumeration eParam = request.getParameterNames();
 while (eParam.hasMoreElements()) {
  String pName = (String)eParam.nextElement();
  String pValue = request.getParameter(pName);

  out.println(pName + " : " + pValue + "<br>");
 }
%>

* 미리 설정한 attribute를 가져오는
<%
 Enumeration eAttr = request.getAttributeNames();
 while (eAttr.hasMoreElements()) {
  String aName = (String)eAttr.nextElement();
  String aValue = request.getHeader(aName);

  out.println(aName + " : " + aValue + "<br>");
 }
%>

'Computer > Web' 카테고리의 다른 글

웹 2.0 기술의 주역 - OpenAPI의 무한한 가능성  (0) 2007.05.10
색상표  (0) 2007.04.26
JSP / request 내부 객체  (1) 2007.03.16
JSP 코드 작성 요령  (1) 2007.03.12
JSP 2.0: 뭐가 바뀌었나? - 4부  (0) 2007.03.12
JSP 2.0: 뭐가 바뀌었나? - 3부  (0) 2007.03.12
TAG

댓글을 달아 주세요

  1. BlogIcon 해토일도류 2009.05.06 06:05 신고  Addr  Edit/Del  Reply

    좋은 자료 감사합니다^^

posted by 희정냥★ 2007. 3. 12. 12:00

JSP 2.0: 뭐가 바뀌었나? - 4부

원문 : http://www.onjava.com/pub/a/onjava/2004/05/12/jsp2part4.html

by Hans Bergsten, JavaServer Pages, 3판의 저자

번역 손권남(kwon37xi_aT_yahoo dOt co DoT kr)

2004/07/30

이번 "JSP 2.0: 뭐가 바뀌었나?" 시리즈의 마지막회에서는 커스텀 태그 라이브러리를 개발하기 쉽게 해주는 두가지 새로운 기법을 알아볼 것이다 : 태그 파일(tag files)과 새롭고 간결해진 태그 핸들러 JAVA API이다.

JSP 태그 파일로 커스텀 액션 개발하기

(주: "커스텀"은 "사용자 정의, 사용자가 따로 만든"이라는 정도의 의미이다. 이미 많은 책들이 커스텀 태그, 커스텀 액션이라는 말을 쓰고 있으므로 번역하지 않는다.)

JSP는 Java의 구루 경지에 오르지 않은 사람들이 동적인 컨텐트를 가진 웹 페이지를 만들 수 있도록 하려고 탄생한 것이다. 지금까지 동적이고 복잡한 컨텐트의 조각들을 여러 페이지간에 재사용하는 것이 약간 힘들었던게 사실이다. 만약 당신이 변수에 저장된 질문과 답변들을 가진 간단한 설문조사를 여러 페이지에 추가하고 싶다고 하자. JSP 2.0 이전에는 세가지 방식이 있었다. 설문조사가 필요한 모든 페이지에 설문조사 코드를 복사해서 붙여넣을 수 있다. 더 나은 방법으로 설문조사 폼을 생성하는 JSP를 따로 제작하고, 설문조사가 필요한 페이지에서 <jsp:include>나 <c:import> 액션으로 이 페이지를 불러들인다. 하지만 제약사항이 있는데, 예를들어 답변같은 것을 인자로 넘겨주기 위해 자바 빈이나 Map 등을 사용하지 못하고 오직 String만을 사용할 수 있다. 세번째 방식으로 Java 태그 핸들러 클래스로 커스텀 액션을 구현하는 것인데, 이것은 Java를 알아야만 한다.

JSP 2.0에는 네번째 방식이 있다: 다시 말해서 태그 파일로 커스텀 액션을 개발하는 것이다. 태그 파일은 정규 JSP페이지 처럼 동적인 부분에 JSP 요소들을 사용할 수 있는 텍스트 파일이다. 이것은 Java 태그 핸들러와 같은 목적으로 만들어진 것이다. 즉, 커스텀 액션을 위한 로직을 제공한다. 태그 파일과 JSP 페이지의 주된 차이점은 태그 파일은 파일 확장자가 .tag이고, 페이지 지시자 대신 태그 지시자를 사용하고 태그 파일에서만 유효한 새로운 몇몇 지시자를 이용해서 입력과 출력을 선언할 수 있다는 것이다.

자세히 한 번 살펴보자. 여기 간단한 설문조사 폼을 만드는 "poll.tag"라는 태그 파일이 있다.

<%@ tag body-content="empty" %>
<%@ attribute name="question" required="true" %>
<%@ attribute name="answers" required="true"
   type="java.lang.Object" %>
<%@ attribute name="votesMapName" required="true" %>
<%@ attribute name="answersMapName" required="true" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>

Question: ${question}<br>
<form action="result.jsp" target="result">
   <input type="hidden" name="question" value="${question}">
   <input type="hidden" name="votesMapName" value="${votesMapName}">
   <input type="hidden" name="answersMapName" value="${answersMapName}">
   <c:forEach items="${answers}" var="a">
      <input type="radio" name="vote" value="${a.key}">${a.value}<br>
   </c:forEach>
   <input type="submit" value="Vote">
</form>

파일 맨 위 태그 지시자가 있다. 태그 지시자는 JSP 페이지에서 사용하는 페이지 지시자와 비슷하게 일반적인 파일의 성격을 규정한다. 여기서 나는 body-content 속성을 사용해서 JSP 페이지에서 이 태그 파일을 나타내는 액션 요소의 값이 비어 있어야 함을 선언했다. 예를 들면, 이 액션 요소는 바디를 가져서는 안된다. 비어있는 값 대신 스크립트가 아닌 값(바디는 스크립팅 요소를 제외하고 어떤 값이든 포함할 수 있다), 혹은 태그 의존값(컨테이너는 바디의 내용을 어떠한 변환도 없이 그대로 태그 핸들러에 넘겨준다) 등을 사용할 수 있다. 커스텀 액션을 자바 클래스로 개발해봤다면, body-content와 유효한 값들이 태그 라이브러리 기술자(Tag Library Descriptor; TLD)에서 왔음을 알 수 있다. 태그 지시자와 다른 특별한 태그 파일 지시자들은 TLD가 JSP 컨테이너에 제공하는 것과 동일한 정보를 제공하기 위해 사용된다.

이 예제에서 태그 지시자 다음에 나오는 attribute 지시자는 동명의 TLD 요소가 하는 것과 같은 역할을 한다. 이것은 유효한 커스텀 액션 요소의 속성을 선언한다. poll 태그 파일은 네가지 속성을 가진다 :

  • question : 설문조사 질문
  • answers : 숫자로 된 키값과 설문조사 답변을 가진 application 스코프의 Map 객체이다.
  • votesMapName : 숫자로된 키와 답변당 득표수를 가지고 있는 application 스코프 Map 객체의 이름.
  • answersMapName: 답변 Map(예를 들면 answers 속성의 값으로 넘겨 받은 Map)을 가지고 있을 어플리케이션 스코프 변수의 이름.

액션 요소 속성 하나당 name 속성으로 선언된 이름을 가진 한개의 attribute 지시자가 있다. 이 예제의 모든 액션 요소 속성은 각 attribute 지시자의 required 속성에 선언된 대로 필수적으로 요구된다. type 속성에 의해 선언된 대로, answers 속성의 값은 Map 객체이어야만 한다. 그외 다른 모든 속성은 기본 형인 String 형이어야한다. 그래서 나는 그러한 속성에는 type 속성을 명시하지 않았다.

이 태그 파일의 나머지는 일반적인 기존 JSP 이다. taglib 지시자가 JSTL core 라이브러리가 이파일에서 사용된다고 선언하고, 파일의 바디에서는 EL 표현식안에서 속성 값들(태그 파일에 페이지 스코프 변수로 생성된)을 사용해서 질문과 각 답변마다 라디오 버튼이 달린 폼을 생성한다. 폼에서 answers와 votes의 Map 변수 이름과 질문은 hidden으로 인코딩 되어 다음과 같은 형태로 사용될 투표 처리하는 페이지로 보내지게 된다 :

<%@ page contentType="text/html" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
   <head>
      <title>Poll Results</title>
   </head>
   <body bgcolor="white">
      <c:set target="${applicationScope[param.votesMapName]}"
        property="${param.vote}"
        value="${applicationScope[param.votesMapName][param.vote] + 1}" />
   
      <p>
        Question: ${param.question}<br>
        <c:forEach items="${applicationScope[param.answersMapName]}"
          var="a">
          ${a.key}) ${a.value}:
          ${applicationScope[param.votesMapName][a.key]}<br>
        </c:forEach>
      </p>
   </body>
</html>

이것은 JSTL 액션을 사용한 평범한 JSP 페이지이다. voteMapName 파라미터에 의해 제공되는 이름으로 어플리케이션 스코프에 존재하는 Map 객체가 투표 결과를 가지고 있는데, 그 객체에 있는 설문조사답변과 키값이 일치하는 변수의 값을 증가시켜준다. 다음으로, 이것은 질문을 출력하고 "answerMapName" 파라미터에 의해 제공되는 어플리케이션 스코프의 설문조사 답변들의 맵 변수를 순회하여 각 답변을 현재 득표수와 함께 출력한다.

우리는 설문조사 투표 처리를 어떻게 하는가 보다는 설문조사 태그 파일을 통해 구현된 커스텀 액션을 어떻게 사용하는지에 더 관심이 있으므로, 여기 예제를 보여준다:

<%@ page contentType="text/html" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="my" tagdir="/WEB-INF/tags/mytags" %>

<html>
   <head>
      <title>My Page</title>
   </head>
   <body bgcolor="white">
      <jsp:useBean id="myAnswers" scope="application"
        class="java.util.TreeMap">
        <c:set target="${myAnswers}" property="1" value="Yes" />
        <c:set target="${myAnswers}" property="2" value="No" />
        <c:set target="${myAnswers}" property="3" value="Maybe" />
      </jsp:useBean>
      <jsp:useBean id="myVotes" scope="application"
        class="java.util.HashMap" />    
      ...
      <p>
        <my:poll question="Will you start using tag files?"
          answers="${myAnswers}"
          answersMapName="myAnswers" votesMapName="myVotes" />
      </p>
      ...
   </body>
</html>

주의해서 볼 첫번째 사항은 태그 파일을 가지고 있는 태그 라이브러리를 선언하는 taglib 지시자이다. TLD를 생성하지 않고 태그 파일을 사용하려면, WEB-INF/tags 디렉토리 아래의 어디엔가 태그 파일을 저장해야만 한다.

poll.tag 예제파일은 WEB-INF/tags/mytags 디렉토리에 저장되었고 이 디렉토리 이름을 taglib 지시자의 'tagdir ' 속성의 값으로 사용했다. 이렇게하여 컨테이너에게 이 디렉토리에 있는 모든 태그 파일이 한개의 동일한 태그 라이브러리에 속한다고 선언하고, 이 라이브러리의 액션을 위한 액션 요소들이 taglib 지시자의 prefix 속성에 지정된 값 - 이 예제에서는 "my" - 을 이용해 구분라고 알려준다. 다른 방법으로, 태그 파일을 TLD파일과 함께 .jar 로 묶을 수 있다. 그리고 태그 라이브러리를 일반적인 커스텀 태그 라이브러리와 마찬가지 방식의 taglib 지시자로 선언할 수 있다. 예를들어, tagdir 속성대신 uri 속성을 사용한다.

이 예제에서, 답변과 투표 결과를 위한 Map 객체는 <jsp:useBean> 액션에 의해 생성되고 JSTL의 <c:set> 액션에 의해 값이 증가된다. 하지만, 물론 다른 어떤 방식으로 객체를 생성해도 된다. (예: 아파치의 Struts 에서는 컨텍스트 리스너나 "plugin" 클래스에서). 객체들어 어떻게 생성되었든지 간에, 태그 파일은 일반적인 JSP 커스텀 액션 요소를 통해 수행된다. 나는 answers 속성의 값으로서 answers Map의 값을 계산하기 위해 EL 표현식을 사용했다. 태그 파일 속성은 EL 표현식을 기본적으로 받아들인다. 하지만 attribute 지시자의 rtexprvalue를 이용해 정적인 값만을 받아들이도록 선언할 수도 있다.

이 페이지를 요청하면, JSP 컨테이너는 다른 것들과 마찬가지로 그것을 처리한다. taglib 지시자와 요소의 선행자(prefix)의 도움을 받아 <my:poll> 커스텀 요소의 구현을 적재한다. 컨테이너는 태그 파일을 자기 나름의 방법으로 처리한다. Tomcat 5 컨테이너는 태그 파일을 Java 태그 핸들러 클래스로 바꾸고 컴파일한 뒤 그것을 실행한다.

커스텀 액션의 바디 처리하기

자바로 작성된 태그 핸들러 클래스와 마찬가지로, 태그 파일도 컨테이너에게 커스텀 액션 요소의 바디를 평가하고, 추가적으로 평가 결과를 더 처리하도록 할 수 있다.

액션 요소의 바디에 설문조사에 관한 짧은 설명을 추가할 수 있도록 만들어보자. 다음과 같다 :

<%@ page contentType="text/html" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="my" tagdir="/WEB-INF/tags/mytags" %>
...
<html>
   ...
   <body bgcolor="white">
      ...
      <p>
        <my:poll question="Will you start using tag files?"
          answers="${myAnswers}"
          answersMapName="myAnswers" votesMapName="myVotes" >
          JSP 2.0 introduces a new way to develop custom action
          tag handlers, called <i>tag files</i>
        </my:poll>
      </p>
      ...
   </body>
</html>

이 예제에서의 바디는 오직 텍스트만을 가지고 있다. 하지만 액션 요소나 EL 표현식이 올 수도 있다. 바디를 평가하고 결과를 출력하기 위해, poll 태그 파일을 다음과 같이 수정할 필요가 있다:

<%@ tag body-content="scriptless" %>
<%@ attribute name="question" required="true" %>
<%@ attribute name="answers" required="true"
   type="java.lang.Object" %>
<%@ attribute name="votesMapName" required="true" %>
<%@ attribute name="answersMapName" required="true" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>

<p>
   <jsp:doBody/>
</p>
Question: ${question}<br>
<form action="result.jsp" target="result">
   <input type="hidden" name="question" value="${question}">
   <input type="hidden" name="votesMapName" value="${votesMapName}">
   <input type="hidden" name="answersMapName" value="${answersMapName}">
   <c:forEach items="${answers}" var="a">
      <input type="radio" name="vote" value="${a.key}">${a.value}<br>
   </c:forEach>
   <input type="submit" value="Vote">
</form>

첫째, 태그 지시자의 body-content 속성의 값을 "scriptless"로 변경한다. 이미 말했다시피, 이렇게 하면 바디는 스크립팅 요소를 제외하고는 어떠한 내용이라도 포함할 수 있게된다. 다음으로, <jsp:doBody>액션을 추가한다. 이를통해 컨테이너가 바디를 평가하고 결과를 출력하게 한다. 다른 방법으로, var 속성을 사용해서 평가 결과를 가져와 다른 처리를 할 수도 있다.

여기서 설명한 기능외에 추가적으로, 태그 파일은 자신을 호출한 파일에 변수를 통해 정보를 돌려줄 수도 있고, 선언되지 않은 속성을 처리하고 단편적인 속성을 가질 수 있다(예: 태그 파일이 액션 요소의 바디를 평가하는 것과 비슷한 방법으로 태그 파일에의해 평가되는 액션 요소와 EL 표현식을 갖고 있는 속성). 이에 대한 모든 사항을 나의 JSP 책 11장에서 볼 수 있다. 온라인에서 샘플로 볼 수 있다.

더 간편해진 Java 태그 핸들러 API

커스텀 액션 태그 핸들러를 태그 파일로 작성할 수 있게 된 것은 특히 많은 양의 HTML을 생성하는 커스텀 액션에서 매우 훌륭한 기능이다. 그러나 몇몇 기능은 단지 JSP 액션과 EL 표현식만으로만 작성하기는 어렵다. 그래서 Java 태그 핸들러 API가 여전히 필요하다. JSP 2.0 이전에는 Java로 태그 핸들러를 작성하는 것이 꽤 까다로왔다. 액션 요소의 바디를 처리하기 위해 컨테이너와 태그 핸들어사이의 복잡한 상호작용이 필요했기 때문이다.

액션 요소 바디에서 Java 스크립팅 요소를 지원하기 위해서 이렇게 복잡하게 되었다. 그러나, 바디가 오직 템플릿 텍스트와 EL 표현식, 액션 요소만 포함하게 된다면, 더욱 단순한 API 디자인이 가능해 진다. 바로 그것이 JSP 2.0에서 이뤄진 것이고, 단순한 태그 핸들러 API(simple tag handler API)라고 불리운다.

좀전에 태그 파일로 구현했던 설문조사 커스텀액션의 Java 태그 핸들러 :

package com.mycompany.mylib;

import java.io.IOException;
import java.util.Iterator;
import java.util.Map;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.JspWriter;
import javax.servlet.jsp.tagext.JspFragment;
import javax.servlet.jsp.tagext.SimpleTagSupport;

public class PollTag extends SimpleTagSupport {
   private String question;
   private Map answers;
   private String votesMapName;
   private String answersMapName;

   public void setQuestion(String question) {
      this.question = question;
   }

   public void setAnswers(Map answers) {
      this.answers = answers;
   }

   public void setVotesMapName(String votesMapName) {
      this.votesMapName = votesMapName;
   }

   public void setAnswersMapName(String answersMapName) {
      this.answersMapName = answersMapName;
   }

   public void doTag() throws JspException, IOException {
      JspWriter out = getJspContext().getOut();
      JspFragment body = getJspBody();
      if (body != null) {
         out.println("<p>");
         body.invoke(null);
         out.println("</p>");
      }
      out.print("Question:");
      out.print(question);
      out.println("<br>");
      out.println("<form action=\"result.jsp\" target=\"result\">");
      out.print("<input type=\"hidden\" name=\"question\" value=\"");
      out.print(question);
      out.println("\">");
      out.print("<input type=\"hidden\" name=\"votesMapName\" value=\"");
      out.print(votesMapName);
      out.println("\">");
      out.print("<input type=\"hidden\" name=\"answersMapName\" value=\"");
      out.print(answersMapName);
      out.println("\">");
      Iterator i = answers.keySet().iterator();
      while (i.hasNext()) {
         String key = (String) i.next();
         String value = (String) answers.get(key);
         out.print("<input type=\"radio\" name=\"vote\" value=\"");
         out.print(key);
         out.print("\">");
         out.print(value);
         out.println("<br>");
      }
      out.println("<input type=\"submit\" value=\"Vote\">");
      out.println("</form>");
   }
}

단순한 태그는 새로운 javax.servlet.jsp.tagext.SimpleTag 인터페이스를 구현해야 한다. 예제의 태그 핸들러는 모든 메소드의 기본적인 구현을 제공해 주는 javax.servlet.jsp.tagext.SimpleTagSupport 클래스를 상속해서 작성했다. 기존의 태그 핸들러 클래스와 마찬가지로, 각각의 커스텀 액션 속성을 위해 셋터 메쏘드(setter methods)가 필요하다. 하지만 처리 메소드는 오직 doTag() 하나만 구현하면 된다.

예제 태그 핸들러에서는, doTag() 메쏘드가 SimpleTagSupport 클래스에서 상속받은 getJspBody() 메소드를 실행함으로써 액션 요소 바디의 실행 대행자(JspFragment의 인스턴스)를 얻는다. 만약 바디가 존재한다면, 태그 핸들러는 수행 결과를 출력에 추가하라는 의미로 null 값을 인자로주어 invoke() 메쏘드를 실행한다. <jsp:doBody> 액션과 마찬가지로, Writer의 인스턴스를 invoke() 메쏘드의 인자로 넘김으로써 결과를 잡아낼 수 있다. 그러면 doTag() 메쏘드는 태그 파일 구현에서 했던 것 처럼 모든 답변을 위한 라디오 단추를 가진 폼 HTML을 출력한다.

기존의 태그 핸들러가 바디를 처리하기위해 세 개의 메쏘드(doStartTag(), doAfterBody() 그리고 doEndTag(). 각 메소드는 컨테이너가 다음에 뭘 할지를 지정하는 값을 리턴한다)를 호출하는데 반해, 지금은 태그 핸들러를 작동시키기 위해 컨테이너가 호출하는 메소드가 오직 한 개이기 때문에, SimpleTag로 태그 핸들러를 구현하는것이 기존 태그 핸들러 API를 이용하는 것보다 훨씬 쉽다. 게다가 단순한 태그 핸들러의 인스턴스는 결코 재사용되지 않기 때문에, 상태를 재설정하는 것에 대해 걱정 꺼도 된다. 상태 재설정하기는 나의 이전 글, "JSP 1.2: Great News for the JSP Community, Part 2" 에서 설명한 대로 상당히 많은 문제를 야기시키는 것으로 알려졌다.

단순한 태그 핸들러의 TLD 선언은 기존 태그 핸들러와 완전히 동일한 방식으로 한다. 하지만 <body-content> TLD 요소는 JSP가 아닌 값을 가져야만 한다. 스크립팅 요소가 단순한 태그 핸들러로 구현된 커스텀 액션 요소의 바디에서 허락되지 않기 때문이다.

이 사항 이외에는 단순한 태그 핸들러로 구현한 커스텀 액션을 사용한는 것은 기존의 태그 핸들러를 사용하는 것과 전혀 다를 바 없다.

단순한 태그 핸들러와 기존 태그 핸들러 모두 javax.faces.jsp.tagext.DynamicAttributes라 고 불리는 새로운 인터페이스를 구현함으로써 선언되지 않은 속성을 지원할 수 있다. 두 형태 모두를 위한 속성은 다른 액션이나 EL 표현식을 포함하는 속성을 위한 JspFragment 형이 될 수 있고 태그 핸들러에 의해 몇번이라도 평가 될 수 있다. 이러한 기능에 대해 나의 책 JavaServer Pages 제3판에서 읽어 볼 수 있다.

마무리

이번 시리즈에서 나는 JSP 2.0에 추가된 모든 새로운 기능을 보여주었다 : Expression Language, 더 나은 오류 처리, 새로운 설정 옵션, 더 나아진 XML 페이지 형식 그리고 태그 핸들러를 개발하기위한 두가지 새로운 방법. 전부 해서, 이러한 개선 사항들은 JSP 페이지를 더욱 쉽게 이해하고 유지보수 할 수 있도록 해준다.

JSP 2.0의 새로운 기능들을 접해보고 싶다면, Apache Tomcat 5를 사용해보라고 권하고 싶다. 톰캣은 새로운 JSP 스펙을 최초로 구현한 JSP 컨테이너이다. Jakarta Project 사이트에서 구할 수 있다.

'Computer > Web' 카테고리의 다른 글

JSP / request 내부 객체  (1) 2007.03.16
JSP 코드 작성 요령  (1) 2007.03.12
JSP 2.0: 뭐가 바뀌었나? - 4부  (0) 2007.03.12
JSP 2.0: 뭐가 바뀌었나? - 3부  (0) 2007.03.12
JSP 2.0: 뭐가 바뀌었나? - 2부  (0) 2007.03.12
JSP 2.0: 뭐가 바뀌었나? - 1부  (0) 2007.03.12
TAG

댓글을 달아 주세요

posted by 희정냥★ 2007. 3. 12. 12:00

JSP 2.0: 뭐가 바뀌었나? - 3부

원문 : http://www.onjava.com/pub/a/onjava/2004/04/21/JSP2part3.html

by Hans Bergsten, JavaServer Pages, 3판의 저자

번역 손권남(kwon37xi_aT_yahoo dOt co DoT kr

2004/04/21

더욱 유연해진 JSP 문서 포맷 규칙

JSP 스펙은 두 가지 형태의 JSP 페이지를 지원한다. 어떤 형태의 텍스트나 마크업이라도 포함하는 일반 JSP 페이지와 XHTML이나 JSP 엘리먼트와 같은 웰폼드(Well-formed) XML 인 JSP 문서(Document)이다. 웰폼드 XML 문서가되려면 JSP 지시자와 스크립트 요소들이 일반 JSP와는 다른 방식으로 기술되어야 한다.

일반 JSP 페이지 JSP 문서
<%@ page 속성목록 %> <jsp:directive.page 속성목록 />
<%@ include file="path"%> <jsp:directive.include file="path" />
<%! 선언 %> <jsp:declaration>선언 </jsp:declaration>
<%= 수식 %> <jsp:expression>수식</jsp>
<% 스크립틀릿 %> <jsp:scriptlet>스크립틀릿</jsp:scriplet>

태그 라이브러리는 JSP 문서에서 XML 네임스페이스로 선언된다. 예를들어 XHTML과 JSP 표준 액션 그리고 JSTL 코어 라이브러리를 사용하는 JSP 문서는 <html> 루트 엘리머튼에 다음과 같은 네임 스페이스 선언을 가져야 한다.

<html
    xmlns="http://www.w3c.org/1999/xhtml"
    xmlns:jsp="http://java.sun.com/JSP/Page"
    xmlns:c="http://java.sun.com/jsp/jstl/core"
    xml:lang="en" lang="en">

xmlns 속성은 기본 네임스페이스를 XHTML의 네임스페이스로 설정한다. xmlns:jsp 속성은 JSP 표준 액션에 정의된 jsp 접두사에 관한 것이고, xmlns:c 속성은 JSTL Core 라이브러리에 의해 정의된 c 접두사에 관한 것이다.

JSP 문서는 처음부터 JSP 명세의 한 부분이었으나 초기에는 선택사항일 뿐이었고 나중에도 많은 제약을 갖고 있었다. JSP 2.0 은 대부분의 제약을 없애고, 매우 쉽게 XML과 JSP를 함께 사용할 수 있게 했다.

JSP 2.0 이전에는 JSP 문서는 <jsp:root>요소를 꼭 포함하여 JSP 컨테이너에게 이것이 JSP 페이지임을 알려주어야만 했다. JSP 2.0은 JSP 문서임을 알려주는 다른 방법을 정의하여 이 제한을 없앴다. 다음 조건들 중 한 가지만 만족하면 JSP 컨테이너는 파일을 JSP 문서로서 처리한다 :

  1. 요청된 경로가 web.xml 파일에서 JSP 속성 그룹의 선언에 <is-xml> 요소를 true로 하여 정의된 URL 패턴과 일치하면 된다. Part 2 에서 JSP 속성 그룹의 선언에 대해 더 자세한 사항을 볼 수 있다.
  2. 요청된 경로의 확장자가 .jspx이고, 이 확장자가 JSP 속성 그룹 선언에서 <is-xml> 요소를 false로 지정하지 않았다면 JSP 문서로 인식한다. 다시 말해 .jspx는 JSP 문서의 기본 확장자이다. 하지만 속성 그룹 선언에 의해 명시적으로 다른 용도로 사용할 수 있다.
  3. 요청된 경로의 확장자가 .jsp이거나 혹은 JSP 속성 그룹 선언의 URL 패턴에 일치하고 최상위 요소(root element)가 <jsp:root>이면 JSP 문서로 간주한다.

이 새로윤 규칙에 의해 JSP 문서를 <jsp:root> 요소가 필요 없는 일반 XHTML 파일처럼(물론 동적 컨텐트를 위해서 JSP 요소를 포함하면서) 작성할 수 있게 되었다. JSP 속성 그룹 선언을 다음과 같이 하면 확장자가 .html인 JSP 문서도 가능하다 :

...
<jsp-config>
  <jsp-property-group>
    <url-pattern>*.html</url-pattern>
    <is-xml>true</is-xml>
  </jsp-property-group>
</jsp-config>
...

XML 요소를 생성하는 새로운 방식

JSP 1.2 명세에 따라 JSP 문서를 작성해보았다면, 거의 대부분 XML 요소의 속성에 동적으로 값을 대입할때 문제가 있음을 발견했을 것이다. 예를 들어, XML 요소의 class 속성에 사용자의 스타일 설정을 가지고 있는 빈(bean) 프라퍼티 값을 대입한다고 하자. 당신은 아마 다음과 같은 시도를 먼저 해볼 것이다 :

<table class="<%= user.getTableClass() %>">

JSP 문서에서 이런 형태의 자바 수식이 JSP 액션 요소의 속성 값으로 사용될 수도 있으나, JSP는 템플릿 텍스트에서는 이러한 문법을 인정하지 않는다. 그러므로 여기서와 같은 방법은 작동하지 않는다.

JSP 액션 요소를 사용하여 속성값을 정하려는 시도 또한 작동하지 않는다:

<table class="<c:out value="${user.tableClass}"/>">

이것은 작동하지 않는다. 웰폼드 XML은 요소의 속성값으로 보다 작다 기호(<)를 포함할 수 없다.

JSP 1.2에서 웰폼드 XML을 준수하면서 동적으로 XML 요소의 속성값을 지정하는 방법은 매우 보기 안좋은 CDATA 섹션을 이용하는 것이다. 이것은 XML 요소의 처음과 끝을 마크업이 아닌 일반 텍스트(동적으로 생성된 값으로 둘러 쌓인)로 간주한다 :

<jsp:text><!CDATA[<table class="]]></jsp:text>
<c:out value="${user.tableClass}""/>
<jsp:text>[CDATA[">]]</jsp:text>

JSP 2.0은 매우 간단한 해결책을 제시해 준다. 템플릿 텍스트 중간에 EL 표현식을 사용하거나 요소를 생성하는 새로운 표준 액션을 사용하면 된다. EL 표현식으로 예제를 바꿔 쓰면 다음과 같다:

<table class="${user.tableClass}">

JSP 2.0 컨테이너는 액션의 속성은 물론 템플릿 텍스트 사이의 EL 표현식을 평가(계산)한다. 그러므로 거의 모든 경우에 이것이 가장 훌륭한 해결책이 된다.

EL 표현식으로 대입하고자 하는 값을 평가할 수 없다면, 그 대신에 3개의 새로운 표준 액션과 속성값을 나타낼 수 있는 아무 JSP 코드나 함께 이용하여 동적으로 XML 요소를 만들어낼 수 있다:

<jsp:element name="table">
  <jsp:attribute name="class">
    <c:out value="${user.tableClass}"/>
  </jsp:attribute>
  <jsp:body>
   ....
  </jsp:body>
</jsp:element>

<jsp:element> 액션은 XML 요소를 만들고 거기 포함된 <jsp:attribute> 요소는 요소의 속성을 만든다. 속성의 값은 <jsp:attribute>의 바디의 평가 결과로 설정된다. 그러므로 이 예에서 사용한 <c:out>을 쓴 것 처럼 요소 값을 생성하는 사용자 정의 액션을 사용하여도 된다. 유사하게 <jsp:body> 요소에 포함된 값을 평가하여 생성될 요소의 값으로 지정할 수 있다.

XML 선언을 위한 새로운 표준 액션

XML 문서는 문서의 맨 위에 XML 선언을 가질 수 있다. 일반적으로 그 뒤에 DOCTYPE 선언이 뒤따른다. JSP 2.0 에서는 <jsp:output> 표준 액션을 이용하여 이 두가지 선언의 생성을 조절할 수 있다.

JSP 문서가 최상위 요소로 <jsp:root> 요소를 가지고 있지 않은 이상(혹은 이 시리즈의 다음 기사에서 다룰 tag 파일을 나타내거나), JSP 컨테이너는 기본적으로 다음과 같은 XML 선언을 생성한다:

<? xml version="1.0" encoding="encodingValue" ?>

encoding 속성의 값은 JSP page 지시자의 contentType 속성에 의해 지정된 문자 인코딩이 되거나 명시적으로 지정하지 않았을 경우에는 UTF-8이 된다. XML 선언이 생성되는 것을 막고 싶을 때(아마도 JSP 문서가 다른 JSP 페이지에 포함될 경우에), JSP 문서에서 <jsp:output> 액션 요소를 사용해 JSP 컨테이너를 설득할 수 있다 :

<jsp:output omit-xml-declaration="true" />

선언 생성을 막기 위해 속성의 값을 'true'나 'yes'로 지정하고, 그렇지 않다면 'false'나 'no'를 사용한다.

DOCTYPE 선언은 XML 파서(브라우저에서 사용되는 것과 같은)에게 이 문서가 어떤 Document Type Declaration(DTD)를 따르는지를 알려준다. 파서는 이 정보를 이용해서 오직 DTD에 의해 선언된 XML 요소만을 포함하고 있는 문서인지를 검사한다. JSP 문서에 의해 생성될 문서에 대한 DOCTYPE 선언을 넣어서는 안된다. 그렇게 하면 JSP 문서 자신이 그 DTD에 따른다고 지정하는 것이 되어버린다. 대신 <jsp:output> 액션을 사용하여 JSP 문서에 의해 생성될 결과 문서의 DTD 선언을 추가할 수 있다 :

<jsp:output doctype-root-element="html"
  doctype-public="-//W3C//DTD XHTML 1.0 Transitional//EN"
  doctype-system="http://www.w3c.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"/>

<jsp:directive.page contentType="text/html" />

이 예에서와 같이 사용하면 <jsp:output> 액션은 결과로 XHTML을 위한 DOCTYPE 선언을 추가한다 :

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"   "http://www.w3c.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

나는 또한 이 예제에서 브라우저가 결과 컨텐트를 어떻게 다뤄야 할지를 판단하게 하기 위해, <jsp:directive.page> 선언에 contentType 속성을 text/html MIME 타임으로 지정하여 포함시켰다. 참고로 XHTML에 맞는 정확한 MIME 타입은 application/xhtml+xml인데, 몇몇 최신 브라우저(특히 Internet Explorer 6)은 그것을 인식하지 못한다. text/html은 대부분의 브라우저들이 어떻게 다뤄야 할지를 아는 XHTML을 위한 MIME 타입으로 통용된다.

마무리

지금까지 보았듯이 JSP 2.0은 매우 쉽게 JSP 페이지를 XML 문서로 작성할 수 있도록 해준다. 이 시리즈의 마지막 편은 커스텀 태그 라이브러리에 관한 새로운 특징들을 알아볼 것이다 : 새로운 태그 파일 형식과 간단한 태그 API.

JSP 2.0의 새로운 기능들을 접해보고 싶다면, Apache Tomcat 5를 사용해보라고 권하고 싶다. 톰캣은 새로운 JSP 스펙을 최초로 구현한 JSP 컨테이너이다. Jakarta Project 사이트에서 구할 수 있다.

'Computer > Web' 카테고리의 다른 글

JSP / request 내부 객체  (1) 2007.03.16
JSP 코드 작성 요령  (1) 2007.03.12
JSP 2.0: 뭐가 바뀌었나? - 4부  (0) 2007.03.12
JSP 2.0: 뭐가 바뀌었나? - 3부  (0) 2007.03.12
JSP 2.0: 뭐가 바뀌었나? - 2부  (0) 2007.03.12
JSP 2.0: 뭐가 바뀌었나? - 1부  (0) 2007.03.12
TAG

댓글을 달아 주세요

posted by 희정냥★ 2007. 3. 12. 11:59

JSP 2.0: 뭐가 바뀌었나? - 2부

원문 : http://www.onjava.com/pub/a/onjava/2003/12/03/JSP2part2.html

by Hans Bergsten, JavaServer Pages, 3판의 저자

번역 손권남(kwon37xi_aT_yahoo dOt co DoT kr

2004/07/29

이것은 JavaServer Pages(JSP) 2.0 명세에 추가된 사항들을 설명하는 시리즈의 두번째 글이다. 1부에서는 새로운 표현식(Expression Language)에 대해서 설명했으나, 알아둘게 더 많이 있다. 이번 회에서는 오류 처리 부문에서의 발전된 모습과 새로운 배치 기술자(deployment descriptor) 기능에 대해 알아볼 것이다. 나는 당신이 JSP 1.2에 익숙하고 JSP Standard Tag Library(JSTL)에 대해 들어보기는 했다고 가정하고 글을 썼다.

JSP Error Pages

JSP나 서블릿에서 JSP 오류 페이지를 사용해 보았다면, 이 페이지를 불러들인 예외에 관해 출력하거나 로그 정보를 보여주기를 바랬을 것이다. 하지만 JSP 1.2에서는 그게 그리 쉬운일이 아니다. 그 이유는 errorPage 선언을 가진 서블릿과 JSP가 예외를 request 속성(attribute으로 전달하고, 서로 다른 속성 이름을 사용하기 때문이다. 오직 JSP 속성 이름으로 전달된 예외만이 자동으로 JSP 오류 페이지에 나타날 뿐이다(exception 스크립트 변수나 ${pageContext.exception} EL을 이용해서).

JSP 2.0에서는 서블릿 명세와 같은 속성이름 - javax.servlet.error.exception으로 변경함으로써 이 문제를 해결했다. 또한, 내장 EL pageContext 변수에 errerData라는 새로운 프라퍼티가 있어, 발생한 문제에 대한 다른 정보들도 제공해 준다. errerData 속성은 javax.servlet.jsp.ErrorData 클래스의 인스턴스이며 다음과 같은 프라퍼티로 빈(Bean)으로써 사용할 수 있다.

프라퍼티 자바 형 설명
requestURI String 요청이 실패한 URI.
servletName String 실패한 JSP나 서블릿의 이름.
statusCode int 실패 상태 코드.
throwable Throwable 오류 페이지를 불러들인 예외.

저 프라퍼티들을 사용하는 JSP 오류 페이지의 예제가 있다 :

<%@ page isErrorPage="true" contentType="text/html" %>
<%@ taglib prefix="log" uri="http://jakarta.apache.org/taglibs/log-1.0" %>

Sorry, but things didn't work out as planned. I've logged as much as
I know about the problem, so rest assured that my master will look
into what's wrong as soon as he's sober.

<jsp:useBean id="now" class="java.util.Date" />
<log:fatal>
  -----
  ${now}
  Request that failed: ${pageContext.errorData.requestURI}
  Status code: ${pageContext.errorData.statusCode}
  Exception: ${pageContext.errorData.throwable}
  -----
</log:fatal>

이 페이지에서 사용자들을 다소 안심시켜주는 메시지와 아파치 자카르타 Taglib 프로젝트의 Log 태그 라이브러리를 사용해서 상세한 로그를 보여준다.

특정 파일이 서블릿과 JSP 페이지의 오류 페이지임을 선언하기 위해, web.xml 파일에서 <error-page> 요소를 사용할 수도 있다.

...
  <error-page>
    <exception-type>java.lang.Throwable</exception-type>
    <location>/error.jsp</location>
  </error-page>
  <error-page>
    <exception-code>500</exception-code>
    <location>/error.jsp</location>
  </error-page>
...

특정 JSP 페이지에 대해서 다른 오류 페이지를 보여주고자 한다면, 페이지 지시자의 errorPage 속성을 이용해서 web.xml의 선언을 오버라이드 할 수 있다.

<%@ page errorPage="/other_error.jsp" contentType="text/html" %>

JSP 문법 오류 보고

JSP 1.2와 2.0간의 작지만 중요한 차이점은 JSP 2.0이 JSP 컨테이너가 jsp:id 기능을 지원하도록 한다는 점이다. 이것은 1.2에서는 단지 "권장사항"일 뿐이었다. JSP 개발자들에게 이것이 무엇을 의미하는가? 바로 JSTL이나 커스텀 태그 라이브러리의 문법 오류 내용이 더욱 쓸만해진다는 것이다.

어떻게 작동하냐구? 컨테이너가 JSP 페이지를 실행 가능한 형태(서블릿 클래스)로 변환할 때, 페이지 내에 선언된 모든 태그 라이브러리를 살펴본다. 한 개 혹은 여러개의 태그 라이브러리 선언이 태그 라이브러리 유효성 검사기(TLV; Tag Library Validator)를 가지고 있다면, 컨테이너가 페이지를 받아들이기 전에 TLV가 페이지의 유효성을 검사할 기회를 주게 된다.

이것은 TLV가 페이지를 분석할 때 XML 뷰(View)를 제공 한다. XML 뷰는, 이름에서 보듯이, 모든 정규 JSP 요소와 템플릿 텍스트(HTML 같은..)를 웰 폼드(Well-Formed) XML 문서로 변환한 것이다.

XML 뷰는 TLV가 모든 커스텀 액션이 올바르게 사용되었는지를 확신하도록 파싱 하는 것을 쉽게 만들어 준다.(예를 들어, 엘리먼트들이 올바르게 중첩되었는가, 함께 나와서는 안되는 속성들이 동일한 액션 요소에 같이 사용되지는 않았는가?)

여기 jsp:id가 온 곳이 있다. 컨테이너는 페이지의 각 커스텀 액션 요소에 ID를 부여하고 ID와 요소의 위치(파일, 줄 번호, 행 번호)간의 맵을 유지한다. 컨테이너는 jsp:id 속성을 ID를 값으로 하여 XML 뷰의 모든 커스텀 액션 요소에 추가한다. TLV가 오류를 발견하면, 오류 메시지에 잘못된 액션 요소의 jsp:id 속성 값을 추가하여 컨테이너에 넘겨주게 된다. 컨테이너는 매핑 정보를 이용해서 잘못된 커스텀 액션 요소의 위치 정보를 사용자에게 보여주는 에러 메시지에 추가한다. 이로 인해 문제점을 찾고 수정하기가 쉬워진다.

모든 JSTL 라이브러리는 TLV를 갖고 있다. 나는 당신이 작성할 커스텀 라이브러리에 TLV를 만들고, 당신이 사용할 서드 파티 라이브러리 개발자들에게도 그렇게 하도록 주장할것을 강력히 권한다.

당신이 XML 뷰와 TLV를 잘 모르겠다면, 내가 2001년에 JSP 1.2에 대해 쓴 글에 간단한 설명을 해 뒀으니 보기 바란다.(JSP 1.2: Great News for the JSP Community).

JSP 배치 기술자(deployment descriptor) 새소식

JSP 2.0 은 이전 JSP 명세에서 그랬던 것 처럼 서블릿 명세에 의해 정의된 배치 기술자(web.xml)파일 형식을 사용한다.

어쨌든, JSP 2.0에는 두가지 중요한 변화가 있다: web.xml의 규칙이 XML 스키마(Schema)로 정의되었고, 대부분의 JSP 관련 설정 아이템들이 새로운 XML 요소로 이동해서 JSP 명세의 제어 하에 놓이게 되었다(서블릿과 JSP 명세간의 결합도(coupling)를 최소화 하기 위해서).

XML 스키마는 XML 문서의 문법 규칙을 설명하는 XML 언어이다(예. 요소가 어떻게 중첩되는가, 요소가 어떤 값을 가질 수 있는가, 값이 중복 될 수 있는가, 그리고 그 외 여러가지). 이건 매우 복잡한 명세이지만 운좋게도, 당신이 web.xml을 작성하기 위해 그 XML 스키마의 문법 규칙을 이해해야 할 필요는 없다. 왜냐하면 서블릿과 JSP 명세는 이해하기 쉬운 도표를 제공하기 때문이다(나의 JavaServer Pages, 제 3판 책은 읽기 쉬운 문법 도표를 포함하고 있다). 그래도 XML 스키마를 공부하고 싶다면 W3C 웹 사이트를 참조하라.

규칙을 예전의 DTD 대신 XML 스키마를 이용해서 선언하는 것의 장점은 XML 스키마는 더욱 세부적이라 web.xml 파일을 파싱할 때 더 많은 오류를 찾을 수 있고, 덕분에 컨테이너들 간의 더 나은 이식성을 가져온다는 것이다.

내 생각에 당신이 더욱 기뻐할 다른 장점으로는 XML 스키마가 web.xml의 최상위 요소들이 어떤 순서로 배열되도 상관없게 만들어 준다는 것이다. 이전 버전의 서블릿과 JSP 명세에서는 예를 들어 <error-page> 요소가 <welcome-file-list> 요소보다 먼저 오기라도 하면 오류를 발생시켰지만, 새로운 버전에서는 그런것도 아무 상관 없다. 그렇더라도 최상위 요소 안에 오는 요소들의 순서는 여전히 엄격한 순서에 따라야만 한다. 어쨌든 당신은 최상위 요소들을 마음대로 할 수 있는 자유를 가졌다.

<servlet> 요소 안에 중첩된 <jsp-file> 요소를 제외하고 모든 JSP 관련 요소들은 <jsp-config>라는 최상위 요소 아래에 함께 묶이게 되었다. <jsp-config>안에 중첩해서 <taglib>요소도 JSP 1.2에서와 같은 문법과 의미로 사용할 수 있다. 하지만 사실 JSP 1.2 이후의 컨테이너에서는 <taglib>가 불필요하다. 컨테이너가 배치된 JAR파일로 부터 자동으로 태그 라이브러리 정의를 뽑아내기 때문이다.

새로운 <jsp-property-group> 하위요소(subelement)는 훨씬 더 관심있게 볼만하다. 이 요소는 특정한 URL패턴에 부합하는 JSP 페이지의 집합에 특정한 설정을 적용할 수 있게 한다. 예를 들어보면:

...
  <jsp-config>
    <jsp-property-group>
      <url-pattern>*.jsp</url-pattern>
      <scripting-invalid>true</scripting-invalid>
    </jsp-property-group>
  </jsp-config>
...

<url-pattern> 요소는 설정을 적용할 JSP 페이지의 집합을 구분한다.다른 중첩된 요소들은 설정 옵션을 정의한다. 이 예제에서는, <scripting-invalid> 요소가 모든 JSP 페이지에서 JSP 스크립팅 요소(Java 코드 같은)를 사용할 수 없게 만든다.

대체로(all in all), 다음과 같은 설정 요소들을 <jsp-property-group> 요소 안에 중첩해서 <scripting-invalid> 요소와 같은 방식으로 사용할 수 있다:

요소 설명
<el-ignored> true이면, URL 패턴이 일치하는 JSP 페이지 내의 EL 표현식을 EL 표현식이 아니라 일반적인 텍스트로써 다루게 된다. 이것은 JSP 1.2에서 EL 표현식처럼 보이는 텍스트를 JSP 2.0 으로 천천히 마이그레이션 하는데 유용하게 사용될 수 있다. 'elIgnored' 페이지 지시자 속성을 이용해서 JSP 2.0으로 변환한 페이지들에서 선택적으로 EL을 사용하게 만들 수도 있다.
<scripting-invalid> true이면, URL 패턴이 일치하는 JSP 페이지에서 스크립팅 요소를 사용하면 번역시(translation-time) 오류를 발생시킨다.
<page-encoding> URL 패턴이 일치하는 모든 JSP 페이지에 대해 지정된 페이지 문자 인코딩을 사용한다. 모든 JSP 페이지에 인코딩을 지정하는 대신 사용할 수 있고, JSP 페이지에 몇몇 특수한 파일 인코딩(예를들면 EBCDIC)을 지정할 수 있는 유일한 방법이다.
<include-coda> URL 패턴이 일치하는 모든 JSP 페이지의 끝에 자동으로 포함될 파일의 컨텍스트에 상대적인 경로를 지정한다. 한개의 <jsp-property-group> 요소 안에서 여러개의 요소를 사용할 수도 있고, 여러개의 <jsp-property-group> 요소에서 사용할 수도 있다.
<include-prelude> URL 패턴이 일치하는 모든 JSP 페이지의 시작 부분에 자동으로 포함될 파일의 컨텍스트에 상대적인 경로를 지정한다. 한개의 <jsp-property-group> 요소 안에서 여러개의 요소를 사용할 수도 있고, 여러개의 <jsp-property-group> 요소에서 사용할 수도 있다.
<is-xml> true이면, URL 패턴이 일치하는 모든 JSP 페이지가 JSP XML 문법을 사용한다고 지정하는 것이다(이것이 JSP 문서이다).

마무리

이번 회에서는 JSP 2.0 오류 처리방식의 개선점과 새로운 배치 기술자의 기능들을 설명했다. 이 시리즈의 다음번 글에서는 JSP 2.0이 XML 컨텐트를 위해 JSP를 사용하는 것이 어떻게 쉬워졌는지와 커스텀 태그 라이브러리에 관련된 새로운 기능들을 알아볼 것이다.

JSP 2.0의 새로운 기능들을 접해보고 싶다면, Apache Tomcat 5를 사용해보라고 권하고 싶다. 톰캣은 새로운 JSP 스펙을 최초로 구현한 JSP 컨테이너이다. Jakarta Project 사이트에서 구할 수 있다.

'Computer > Web' 카테고리의 다른 글

JSP / request 내부 객체  (1) 2007.03.16
JSP 코드 작성 요령  (1) 2007.03.12
JSP 2.0: 뭐가 바뀌었나? - 4부  (0) 2007.03.12
JSP 2.0: 뭐가 바뀌었나? - 3부  (0) 2007.03.12
JSP 2.0: 뭐가 바뀌었나? - 2부  (0) 2007.03.12
JSP 2.0: 뭐가 바뀌었나? - 1부  (0) 2007.03.12
TAG

댓글을 달아 주세요

posted by 희정냥★ 2007. 3. 12. 11:58

JSP 2.0: 뭐가 바뀌었나? - 1부

원문 : http://www.onjava.com/pub/a/onjava/2003/11/05/jsp.html

by Hans Bergsten, JavaServer Pages, 3판의 저자

번역 손권남(kwon37xi_aT_yahoo dOt co DoT kr)

2004/07/06

기다림이 거의 끝나간다(번역시점에서는 이미 끝났다). 최신 JavaServer Pages(JSP)스펙인 JSP 2.0이 다른 J2EE 1.4스펙과 함께 발표될 때가 가까워왔다. 소수점 앞부분의 버전 번호가 바뀐것으로 보아 JSP를 사용하는 많은 방식들이 바뀌었음을 알 수 있다. 더이상 JSP페이지에 JAVA 코드는 필요없다. 새로운 표현식(EL:Expression Language)과 JSP Standard Tag Library(JSTL)덕분이다. 또한 커스텀 액션을 개발하는 새로운 방식덕분에 코드 재사용이 훨씬 쉬워졌다. 보다 명확하게 말해, JSP 2.0은 다음과 같은 이점들을 가지고 있다.

  • JSTL 1.0 스펙에서 소개되었던 EL(Expression Language)이 JSP 스펙에 포함되었다. EL을 이제는 템플릿 텍스트(HTML 등)에서 뿐만 아니라 모든 표준/사용자 정의 컴포넌트에서 사용할 수 있다.
  • EL이 JSP 1.1이 이용하는 함수 호출 메카니즘까지 확장되었고, 일반적으로 사용되는 함수 모음을 미리 준비해 놓았다.
  • 서블릿 스펙에 정의된 오류 처리 메카니즘으로 정돈된 새로운 변수들을 통해, JSP 오류 페이지가 이제는 오류에 대한 더 많은 정보에 접근할 수 있게 되었다.
  • JSP컨테이너가 JSP문법 오류를 보고하는 방법에관한 요구사항이 까다로와져서 오류를 찾기가 더 쉬워졌다.
  • JSP 2.0과 Servlet 2.4를 포함한 모든 J2EE 1.4스펙은 배포 기술자 규칙(the deployment descriptor rules)의 선언을 XML스키마를 사용해서 한다. 이 방식의 한가지 장점은 이제 web.xml의 선언을 아무 순서로나 배치해도 된다는 것이다. JSP 2.0은 또한 배포기술자에 많은 새로운 설정 옵션들을 추가하여 각 페이지마다 설정하는 대신 전체적으로 설정하는 것을 가능케하였다.
  • JSP 페이지를 XML 문서화하는 것이 더 쉬워졌다. 새로운 유연한 규칙들과 표준 액션 엘리먼트들 덕분이다.
  • 커스텀 태그 라이브러리를 tag 파일(JSP 요소를 가진 텍스트 파일)의 묶음으로 만들수 있게 되었다. 그리고 Java 클래스로 구현된 태그 핸들러는 새롭고 단순화된 태그 핸들러 API를 사용할 수 있게 되었다. 동시에, 동적 속성 목록이나 실행 가능한 프래그먼트 속성(executable fragment attributes)와 같은 많은 새로운 특징들이 추가되었다.

이 기사는 JSP 2.0 의 새로운 기능을 설명하는 기사 시리즈의 첫번째 이다. 이번 장에서는 EL과 관련된 사항만 볼 것이며, 다른 사항들은 다음 회에 보기로 한다. 나는 당신이 JSP 1.2에 익숙하고 JSP Standard Tag Library(JSTL)에 대해 들어보기는 했다고 가정하고 글을 썼다.

당신은 또한 나의 JavaServer Pages 책 3판에 관심이 있을 지도 모른다. 이 책은 이제 설명할 모든 것을 더 자세히 설명하고, 당신이 JSP와 JSTL을 모를 수도 있다고 생각하고 쓴 것이다. 이 책은 2003년 12월에 출간될 예정이다. 하지만 Amazon.com 등의 서점에서 미리 주문할 수도 있다.

Expression Language (EL)

당신이 JSTL을 사용해봤다면, 이미 JSP Expression Lnaguage를 잘 알고 있을 것이다. EL은 JSTL 1.0 스펙에서 소개된 것으로 JAVA코드를 대신해 실행시간에 액션(태그) 엘리먼트의 속성에 값을 지정하는 역할을 한다. JSTL의 EL은 매우 빨리 인기를 끌었다. 하지만 문제가 하나 있는데 JSTL EL은 오직 JSTL 액션에서만 작동했고, 커스텀 액션은 표준이 아닌 API를 사용해서 EL을 수행하도록 특별히 작성되어야만 EL을 사용할 수 있었다.

JSP 2.0을 시작하며, JSP 컨테이너 자신이 EL 표현식을 해석할 수 있게 되었고, 표준과 커스텀 액션 그리고, 템플릿 텍스트(HTML같은)와 같이 JAVA 코드를 사용해야 했던 모든 곳에서 EL을 사용할 수 있게 되었다.

구체적인 예제를 보기전에, EL이 뭔지 더 자세히 살펴보자. EL은 JavaScript에서 조금 확장하고 XPath(XML 문서의 정보에 접근하기 위해 사용되는 언어)에서 힌트를 얻어 만들어진 언어이다. 그러나 EL은 값이 없는 변수(null)에 대해 좀더 관대하고, 데이타형 변환을 좀더 자동적으로 해준다. 이러한 특징들은 파라미터들을 폼에서 얻어오는 웹 어플리케이션에 중요하다. 파라미터들이 몇몇 요청에서는 존재하고 어떤 경우에는 값이 없을 수 있으며, 브라우저가 파라미터값을 항상 문자열(text)로 보내는데 반해, 웹 어플리케이션에서는 숫자나 불린(true/false)로 사용해야 할 경우도 생긴다. EL이 설계된 방식에 따르면, 값이 없을 경우(null)나, 형 변환 같은 것에 전혀 신경쓸 필요가 없다.

EL 표현식은 변수와 연산자를 포함한다. JSP 스코프(page, request, session, application)에 저장된 어떤 빈이라도 EL 변수로서 사용될 수 있다. 게다가 EL은 다음과 같은 내장 변수들도 지원한다:

변수 이름 설명
pageScope 모든 page 스코프 변수에 대한 컬렉션(java.util.Map).
requestScope 모든 request 스코프 변수에 대한 컬렉션(java.util.Map).
sessionScope 모든 session 스코프 변수에 대한 컬렉션( java.util.Map).
applicationScope 모든 application 스코프 변수에 대한 컬렉션(java.util.Map)
param 모든 request 파라미터 값들을 한개의 문자열로 가진 컬렉션(java.util.Map).
paramValues 모든 request 파라미터의 값들을 파라미터당 문자열 배열로 가진 컬렉션(java.util.Map).
header 모든 헤더의 값들을 헤더당 하나의 문자열로 가진 컬렉션(java.util.Map).
headerValues 모든 헤더의 값들을 헤더당 문자열 배열로 가진 컬렉션(java.util.Map).
cookie 모든 쿠키의 값들을 쿠키당 한개의 javax.servlet.http.Cookie의 값으로 가진 컬렉션(java.util.Map).
initParam 모든 어플리케이션의 초기화 파라미터를 파라미터당 한개의 문자열로 가진 컬렉션(java.util.Map).
pageContext javax.servlet.jsp.PageContext 클래스로서, 다양한 request 데이타에 대한 액세스를 가능케 한다.

연산자들은 변수들로 뭘 할 것인지를 지정하는 것이다. EL에서 사용할 수 있는 연산자들은 프로그래밍을 해봤다면 많이 눈에 익을 것이다. 왜냐면, 거의 모든 언어에서 지원되는 연산자들과 같기 때문이다.

연산자 설명
. 빈의 프라퍼티나 Map의 엔트리 접근
[] 배열이나 리스트 엘리먼트 접근
() 부가적인 표현식을 연산 순서를 바꿔서 연산하게 할 때. 3 * (1+2)
? : 조건 테스트 - 조건 ? true일때리턴값 : false일때리턴값
+ 더하기
- 빼기 혹은 음수
* 곱하기
/ 혹은 div 나누기
% 혹은 mod 나머지
== 혹은 eq 같다
!= 혹은 ne 다르다
< 혹은 lt 보다 작다
> 혹은 gt 보다 크다
<= 혹은 le 작거나 같다
>= 혹은 ge 크거나 같다
&& 혹은 and 논리 AND
|| ('|'가 연속으로 두개) 혹은 or 논리 OR
! 혹은 not 단항 not (true를 false로 false를 true로)
empty 빈 변수 값(null, 빈 문자열, 빈 배열, 엔트리가 없는 맵이나 컬렉션)인가 테스트
func(args) 함수 호출. func는 함수 이름이고 args는 없거나, 한개 혹은 쉼표(,)로 분리된 여러개의 함수 인자이다

EL 표현식은 숫자, 문자열(홑따옴표 혹은 쌍 따옴표와 함께), 불린 값과 null같은 리터럴(상수 값)들도 포함할 수 있다.

EL 표현식이 템플릿 문자열(HTML등)이 오는 곧에도 올 수 있기 때문에, JSP 컨테이너에게 그것이 EL표현식이라고 알려줘야만 한다. 구획문자(delimiter)를 이용해서 하면 된다. EL은 항상 ${ 구획문자로 시작해서 }로 끝난다. 여기 5를 amount라는 변수에 더하는 EL 표현식이 있다.

${amount + 5}

빈 프라퍼티에 5를 더하고자한다면, 프라퍼티 접근 연산자를 사용하면 된다:

${order.amount + 5}

프라퍼티 접근 연산자(.)은 EL에게 빈이나 컬렉션(여기서는 order, 빈이나 java.util.Map 일 수 있다)에서 그 다음에 오는 이름과 같은 프라퍼티(여기서는 amount)를 찾게한다.

대신, 배열 접근 연산자를 사용해도 된다.

${order['amount'] + 5}

[] 안의 값은 프라퍼티의 이름을 나타내는 문자열(이 예제에서 쓰인대로)이거나 아니면 프라퍼티 이름을 값으로 가진 변수 (혹은 다른 EL 표현식)이면 된다.

EL은 동적으로 값을 받도록(dynamic value 혹은 request-time attribute) 지정된 표준(JSTL)이나 커스텀 JSP 액션의 속성에 값을 지정할 때도 사용할 수 있다 :

<c:out value="${order.amount + 5}"/>

JSP 2.0 이전에는 속성에 동적으로 값을 주기 위해 JAVA 표현식을 써야만 했다. 이로인해 우리는 지난 몇년간 수많은 문법 오류에 시달려야만 했다.

마침내 EL 표현식이 페이지 내에서 템플릿 텍스트와 직접적으로 함께 쓰일 수 있게 되었다. 이것은 HTML 엘리먼트와 속성을 동적으로 지정해야 할 때 매우 편리하다.

<input name="firstName" value="${customer.firstName}">

JSP 1.2 에서는, 같은 작업을 하기 위해 JSTL의 <c:out> 액션을 사용해야만 했다. 이것은 서로 다른 형의 두 엘리먼트를 섞어써서 이해하기 매우 어렵다 :

<input name="firstName"
    value="<c:out value="${customer.firstName}"/>" >

새로운 JSTL 1.1 태그 라이브러리 지정자

JSTL 1.1은 JSTL을 JSP 2.0에 통합하기 위한 마이너 스펙 릴리즈이다. 눈에 띄는 변화는 JSTL 1.0의 두개로 분리되있던 라이브러리(한가지는 EL를 사용하고 한가지는 JAVA 표현식을 사용하는)가 EL과 JAVA 표현식 모두를 사용할 수 있는 한가지 라이브러리로 통합된 것이다.

JSTL 1.1의 라이브러리들은 다음과 같은 지정자를 사용해야 한다. 1.0과 다르니 주의해야 한다.

Library URI Prefix
Core http://java.sun.com/jsp/jstl/core c
XML processing http://java.sun.com/jsp/jstl/xml x
I18N formatting http://java.sun.com/jsp/jstl/fmt fmt
Database access http://java.sun.com/jsp/jstl/sql sql
Functions http://java.sun.com/jsp/jstl/functions fn

JSTL 1.0을 사용했었다면, 모든 라이브러리의 URI의 중간에 '/jsp' 패스가 들어간 것을 제외하고, 기존의 라이브러리 지정자와 동일함을 알 수 있다. 또한, JSTL 1.1이 EL Function 이라는 새로운 라이브러리를 포함하고 있음도 볼 수 있다. 이것을 짧게 살펴볼 것이다.

새로운 EL 연산자

JSP 페이지에서 매우 자주 필요한 기능 중의 하나는 어떤 조건이 true 일 때 템플릿 텍스트를 포함시키는 기능이다. JSP 1.2와 JSTL 1.1을 이용하면, 이것을 <c:if> 블록을 이용해서 할 수 있다. 하지만, 그건 무척 복잡한 해결책이다. JSP 2.0은 EL에 새로운 조건 연산자를 추가하여 더욱 고상하게 이런 문제를 처리할 수 있다.

조건 연사자는 많은 프로그래밍 언어에 존재하므로(예를 들어 JAVA, C, JavaScript 등). 이미 본적이 있을 것이다. 이 연산자는 불린 조건과 조건이 참일때 사용할 값과 조건이 거짓일 때 사용할 또 다른 값을 취한다. 예제를 보면 어떻게 돌아가는지 확실히 알 수 있을 것이다:

<select name="artist">
 <option value="1" ${param.artist == 1 ? 'selected' : ''}>
 Vesica Pisces
 <option value="2" ${param.artist == 2 ? 'selected' : ''}>
 Cortical Control
 <option value="3" ${param.artist == 3 ? 'selected' : ''}>
 Vida Vierra
</select>

여기서 나는 select 목록에서 입력된 값에 일치하는 값을 가지는 option에 selected 속성을 지정하기 위해 조건 연산자를 사용했다. 만약 조건 (param.artist == 1)이 true이면, 첫번째 결과 ('selected')가 페이지에 추가된다. 그렇지않으면 두번째 값(빈 문자열)이 추가된다.

EL 함수

EL이 JSTL스펙에서 JSP 스펙으로 넘어가면서, 새로운 묘기를 추가했다. 다시말해 함수를 호출하는 방법이다. EL 함수 문법은 단순하다. 인자들을 괄호안에 가지고 있는 함수의 이름:

<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>

${fn:length(myCollection)}

함수는 태그 라이브러리에 속하는 것이고, 함수 이름은 각 페이지의 태그 라이브러리 지시자를 통해 라이브러리에 지정된 prefix를 포함한다.

태그 라이브러리 기술자(TLD; Tag Library Descriptor)는 함수 이름을 함수의 기능을 구현한 자바 클래스의 static 메소드로 매핑한다.

<function>
<description>
컬렉션의 아이템 갯수나 문자열의 문자 갯수를 리턴한다.
</description>
<name>length</name>
<function-class>
org.apache.taglibs.standard.functions.Functions
</function-class>
<function-signature>
int length(java.lang.Object)
</function-signature>
</function>

여기서 가장 주의해서 볼 것은 <function-signature> 엘리먼트이다. 여기에 함수가 리턴할 값의 형에 대한 선언, static으로 구현한 메소드의 이름, 그리고 괄호안에 모든 인수(없거나 1개 이상, 쉼표로 분리)의 형 선언한 것이 포함된다. 리턴 형과 인수의 형은 JAVA 원시형이거나 완전한(패키지까지 포함한) 형 이름이어야 한다.

length() 함수에 대한 static 메소드는 Jakarta Taglibs Standard library에서는 아래와 같이 구현되어있다:

public static int length(Object obj) throws JspTagException {
if (obj == null)
    return 0;
if (obj instanceof String)
    return ((String)obj).length();
if (obj instanceof Collection)
    return ((Collection)obj).size();
if (obj instanceof Map)
    return ((Map)obj).size();

int count = 0;
if (obj instanceof Iterator) {
    Iterator iter = (Iterator) obj;
    count = 0;
    while (iter.hasNext()) {
        count++;
        iter.next();
    }
    return count;
}
if (obj instanceof Enumeration) {
    Enumeration enum = (Enumeration) obj;
    count = 0;
    while (enum.hasMoreElements()) {
        count++;
        enum.nextElement();
    }
    return count;
}
try {
    count = Array.getLength(obj);
    return count;
} catch (IllegalArgumentException ex) {}
    throw new JspTagException("Unsupported type");
}

여기 보듯이, 별로 낯설것이 없다. 이건 그냥 평범한 static 메소드로 인수의 특정한 런타임 형에 따라 length를 구하는 것이다.

여기서 예로든 length() 메소드 외에도, JSTL 1.1 함수 태그 라이브러리는 자주 사용되는 많은 함수들을 포함하고 있다:

함수 설명
fn:contains(string, substring) string이 substring을 포함하면 true 리턴.
fn:containsIgnoreCase(string, substring) 대소문자에 관계없이, string이 substring을 포함하면 true 리턴.
fn:endsWith(string, suffix) string이 suffix로 끝나면 true 리턴.
fn:escapeXml(string) string에 XML과 HTML에서 특별한 의미를 가진 문자들이 있으면, XML 엔티티 코드로 바꿔준 뒤 문자열 리턴.
fn:indexOf(string, substring) string에서 substring이 처음으로 나타나는 인덱스 리턴.
fn:join(array, separator) array(배열) 요소들을 separator를 구분자로 하여 연결해서 리턴
fn:length(item) item 이 배열이나 컬렉션이면 요소의 갯수를, 문자열이면 문자의 갯수를 리턴.
fn:replace(string, before, after) string 내에 있는 before 문자열을 after 문자열로 모두 바꿔서 리턴.
fn:split(string, separator) string 내의 문자열을 separator에 따라 나누어서 배열로 구성해 리턴.
fn:startsWith(string, prefix) string이 prefix로 시작하면 true 리턴.
fn:substring(string, begin, end) string에서 begin 인덱스에서 시작해서 end 인덱스에 끝나는 부분(end 인덱스에 있는문자 포함)의 문자열을 리턴.
fn:substringAfter(string, substring) string에서 substring이 나타나는 이후의 부분에 있는 문자열을 리턴.
fn:substringBefore(string, substring) string에서 substring이 나타나기 이전의 부분에 있는 문자열을 리턴.
fn:toLowerCase(string) string을 모두 소문자로 바꿔 리턴.
fn:toUpperCase(string) string을 모두 대문자로 바꿔 리턴.
fn:trim(string) string 앞뒤의 공백(whitespace)을 모두 제거하여 리턴.

마무리

이 글에서, 새로운 EL의 특징과 JSTL 1.1 함수 라이브러리 등 JSP 스펙에 도입된 EL을 다루었다. 다음 회에서는 JSP의 오류 페이지(error-page)의 향상과 jsp:id 속성의 이점, 새로운 배치 기술자(deployment descriptor)의 형식, JSP 2.0 이 JSP와 XML 사용을 어떻게 쉽게 만들어주는가, 그리고 커스텀 태그 라이브러리에 관한 사항들을 다룰 것이다.

JSP 2.0의 새로운 기능들을 접해보고 싶다면, Apache Tomcat 5를 사용해보라고 권하고 싶다. 톰캣은 새로운 JSP 스펙을 최초로 구현한 JSP 컨테이너이다. Jakarta Project 사이트에서 구할 수 있다.

'Computer > Web' 카테고리의 다른 글

JSP / request 내부 객체  (1) 2007.03.16
JSP 코드 작성 요령  (1) 2007.03.12
JSP 2.0: 뭐가 바뀌었나? - 4부  (0) 2007.03.12
JSP 2.0: 뭐가 바뀌었나? - 3부  (0) 2007.03.12
JSP 2.0: 뭐가 바뀌었나? - 2부  (0) 2007.03.12
JSP 2.0: 뭐가 바뀌었나? - 1부  (0) 2007.03.12
TAG

댓글을 달아 주세요