상세 컨텐츠

본문 제목

JSTL 기초, Part 4: SQL과 XML 콘텐트에 액세스 하기 (한글) - JSP 페이지에서 XML과 데이터베이스 콘텐트를 교환하는 커스텀 태그 라이브러리

프로그래밍/JAVA

by 라제폰 2009. 3. 6. 20:00

본문

난이도 : 중급

Mark Kolb, Software Engineer

2007 년 4 월 03 일

웹 기반 애플리케이션의 정수는 여러 개의 하위 시스템들을 통합하는 것입니다. 이 같은 하위 시스템들간 데이터 교환에 사용되는 두 가지의 가장 일반적인 메커니즘은 SQL과 XML 입니다. 이 글에서, Mark Kolb는 JSTL 시리즈를 마감하면서, JSP 페이지에서 데이터베이스와 XML 콘텐트에 액세스 하는 sqlxml 라이브러리를 설명합니다.

웹 기반 애플리케이션용 기본 아키텍처는 세 개의 티어(tier)를 필요로 한다. 요청을 처리하는 웹 서버, 비즈니스 로직을 구현하는 애플리케이션 서버, 영속성의 데이터를 관리하는 데이터베이스이다. 애플리케이션과 데이터베이스 티어들 간 연결은 SQL 호출의 형태를 취해서 관계형 데이터베이스로 가져온다. 비즈니스 로직이 자바로 작성될 때, JDBC가 이러한 호출들을 실행하는데 사용된다.

애플리케이션이 추가 (로컬 또는 원격) 서버들과의 통합을 필요로 한다면, 다양한 하위 시스템들간 데이터를 교환하는 메커니즘이 필요하며, 웹 애플리케이션 내에서 그리고 웹 애플리케이션들 간 데이터 통신 방식은 XML 문서 교환으로 일반화 되고 있다.

지금까지, JSTL 시리즈를 통해서 JSTL expression language(EL)와 core , fmt 태그 라이브러리를 설명했다. 이 마지막 시리즈에서는 SQL 데이터베이스와 XML 문서에서sql, xml 라이브러리에서 제공되는 커스텀 태그를 통해 데이터 액세스 및 조작에 대해 설명하겠다.

이 기사의 다른 시리즈
Part 1, "Expression language" (2003년 2월)

Part 2, "core 분석" (2003년 3월)

Part 3, "보여지는 것도 중요하다!" (2007년 3월)

xml 라이브러리

디자인 측면으로 볼 때, XML은 구조화 된 데이터를 나타내는 유연한 수단이며, 특히 약결합(loosely coupled) 시스템들간 데이터 교환에 특히 잘 맞는다. 이것은 웹 기반 애플리케이션에 있어서 매력적인 통합 기술이다.

XML로 표현된 데이터와 상호작용 하는 첫 단계는 이것을 XML 문서로 가져와서 이를 파싱하여 문서의 내용에 액세스 할 수 있는 데이터 구조를 만드는 것이다. 문서가 파싱 된 후에, 이를 변형하여 새로운 XML 문서를 만들 수 있는데, 같은 연산이 다시 적용될 수 있다. 마지막으로, 이 문서에서 온 데이터가 추출될 수 있고 추가 연산을 수행하는 인풋으로서 디스플레이 또는 사용될 수 있다.

이 단계는 XML을 조작하는데 사용되는 JSTL 태그를 모방한 것이다. XML 문서들은 Part 2, core 분석에서 설명한 것처럼 core 라이브러리에서 <c:import> 태그를 사용하여 검색된다. <x:parse> 태그는 이 문서를 파싱하는데 사용되고, Document Object Model (DOM)과 Simple API for XML (SAX) 같은 표준 XML 파싱 기술의 지원을 받는다. <x:transform> 태그는 XML을 변형하는데 사용되고, XML 데이터를 변형하는 표준 기술인 Extensible Stylesheet Language(XSL)에 의존하고 있다. 마지막으로, 파싱 된 XML 데이터에 액세스 하여 조작하는데 사용되는 여러 태그들을 제공하고, 이 모두가 파싱 된 XML 문서들의 내용을 참조하는데 XML Path Language(XPath)라는 표준을 따르고 있다.

XML 파싱하기

<x:parse> 태그는 원하는 파싱 유형에 따라 여러 형태를 취한다. 가장 기본적인 형태는 다음과 같은 문법을 사용한다.

<x:parse xml="expression
" var="
name
" scope="
scope"
    filter="expression
" systemId="
expression"/>

다섯 개의 애트리뷰트 중에서 xml 애트리뷰트만 필요하고, 이것의 값은 파싱 될 XML 문서를 포함하고 있는 String이거나 파싱 된 문서가 읽힐 수 있는 java.io.Reader의 인스턴스가 되어야 한다. 다음 문법을 사용하여, <x:parse> 태그의 바디 콘텐트로서 문서가 파싱 되도록 지정할 수 있다.

<x:parse var="name
" scope="
scope"
    filter="expression
" systemId="
expression">
  body content
</x:parse>

varscope 애트리뷰트는 파싱 된 문서를 저장하기 위한 범위가 지정된 변수를 지정한다. 이 변수는 xml 라이브러리의 다른 태그들에 의해 사용되어 추가 연산을 수행한다. varscope 애트리뷰트가 있다면, 파싱 된 문서를 나타내기 위해 JSTL에서 사용되는 데이터 구조의 유형은 벤더들 마다 다르다.

애플리케이션이 JSTL에서 제공된 파싱 된 문서에 대한 연산을 수행해야 한다면, <x:parse>의 대안 폼이 사용될 수 있는데, 이때 파싱 된 문서는 표준 인터페이스에 순응해야 한다. 이 경우, 태그용 문법은 다음과 같다.

<x:parse xml="expression
" varDom="
name
" scopeDom="
scope"
    filter="expression
" systemId="
expression"/>

이 버전의 <x:parse>를 사용할 때, 파싱 된 XML 문서를 나타내는 객체는 org.w3c.dom.Document 인터페이스를 실행해야 한다. XML 문서가 <x:parse>의 바디 콘텐트로서 지정될 때 varscope 대신에 varDomscopeDom 애트리뷰트를 사용할 수 있다:

<x:parse varDom="name
" scopeDom="
scope"
    filter="expression
" systemId="
expression">
  body content
</x:parse>

나머지 두 개의 애트리뷰트인 filtersystemId는 보다 세분화 된 파싱을 실행한다. filter 애트리뷰트는 org.xml.sax.XMLFilter 클래스의 인스턴스를 지정하여 파싱 전에 문서를 걸러낸다. 이 애트리뷰트는 파싱 될 문서가 매우 클 때 특히 유용하며, 작은 하위 세트에도 유용하다. systemId 애트리뷰트는 파싱되고 있는 문서용 URI를 가리키고, 문서에 있는 상대 경로를 나타낸다. 이 애트리뷰트는 파싱되고 있는 XML이 상대 URL을 사용하여 파싱 프로세스 동안 액세스 되어야 하는 다른 문서나 리소스를 참조할 경우에 필요하다.

Listing 1은 <x:parse> 태그의 사용법을 나타내고 있고, <c:import>와의 인터랙션도 포함되어 있다. 여기에서, <c:import> 태그는 잘 알려진 Slashdot 웹 사이트의 RDF Site Summary (RSS) 피드를 가져오는데 사용된다. RSS 피드를 나타내는 XML 문서는 <x:parse>에 의해 파싱되고, 파싱 된 문서를 표현하는 데이터 구조는 rss 변수와 page 범위에 저장된다.


Listing 1. <x:parse>와 <c:import> 액션들간 인터랙션
				
<c:import var="rssFeed" url="http://slashdot.org/slashdot.rdf"/>
<x:parse var="rss" xml="${rssFeed}"/>

XML 변형하기

XML은 XSL 스타일시트로 변형되며, JSTL은 <x:transform> 태그를 사용하여 이 연산을 지원한다. <x:parse>의 경우처럼, <x:transform> 태그는 여러 개의 다른 형태들을 지원한다. <x:transform>의 가장 기본적인 형태의 문법은 다음과 같다.

<x:transform xml="expression
" xslt="
expression"
    var="name
" scope="
scope"
    xmlSystemId="expression
" xsltSystemId="
expression">
  <x:param name="expression
" value="
expression"/>
  ...
</x:transform>

RSS

RDF Site Summary (RSS)는 많은 뉴스를 제공하는 사이트에서 제공하는 XML 문서 포맷으로서, 현재의 헤드라인을 리스팅 하고, 그에 해당하는 기사들로 연결되는 URL을 제공한다. 웹을 통해서 뉴스 아이템을 합성하는 간단한 메커니즘을 제공하는 것이다. RSS에 대한 자세한 내용은 참고자료를 참조하라.

여기에서, xml 애트리뷰트는 변형될 문서를 지정하고, xslt 애트리뷰트는 그러한 변형을 정의하는 스타일시트를 지정한다. 이러한 두 개의 애트리뷰트가 필수적인 것이고, 나머지는 선택이다.

<x:parse>xml 애트리뷰트처럼, <x:transform>xml 애트리뷰트의 값은 XML 문서를 포함하고 있는 String이거나, 문서에 액세스 할 수 있는 Reader가 될 수 있다. 또한, org.w3c.dom.Document 클래스 또는 javax.xml.transform.Source 클래스의 인스턴스 형태를 취할 수 있다. 마지막으로, <x:parse> 액션의 varvarDom 애트리뷰트 중 하나를 사용하여 할당된 변수의 값이 될 수 있다.

<x:transform> 액션의 바디 콘텐트로서 변형될 XML 문서도 포함시킬 수 있다. 이 경우, <x:transform>의 문법은 다음과 같다.

<x:transform xslt="expression"
    var="name
" scope="
scope"
    xmlSystemId="expression
" xsltSystemId="
expression">
  body content
  <x:param name="expression
" value="
expression"/>
  ...
</x:transform>

두 경우 모두, XSL 스타일시트를 지정하는 xslt 애트리뷰트는 String이나 Reader 또는 javax.xml.transform.Source의 인스턴스가 되어야 한다.

var 애트리뷰트가 있다면, 변형된 XML 문서는 org.w3c.dom.Document 클래스의 인스턴스로서 상응하는 범위 지정 변수에 할당되며, 일반적으로 scope 애트리뷰트는 변수 할당의 범위를 지정한다.

<x:transform> 태그는 org.w3c.dom.Document의 인스턴스 보다는 javax.xml.transform.Result 클래스의 인스턴스에 변형 결과를 저장한다. varscope 애트리뷰트가 생략되고 Result 객체가 result 애트리뷰트의 값으로서 지정되면, <x:transform> 태그는 그 객체를 사용하여 스타일시트를 사용한 결과를 저장할 것이다. <x:transform>result 애트리뷰트를 사용하는 두 가지 문법 변화는 Listing 2에 나타나 있다.


Listing 2. javax.xml.transform.Result instance를 제공하기 위해 Result 애트리뷰트를 사용할 때 <x:transform> 액션에 대한 문법 변화
				
<x:transform xml="expression
" xslt="
expression"
    result="expression"
    xmlSystemId="expression
" xsltSystemId="
expression">
  <x:param name="expression
" value="
expression"/>
  ...
</x:transform>

<x:transform xslt="expression"
    result="expression"
    xmlSystemId="expression
" xsltSystemId="
expression">
  body content
  <x:param name="expression
" value="
expression"/>
  ...
</x:transform>

<x:transform>의 두 형태들 중 하나를 사용할 때, javax.xml.transform.Result 객체는 커스텀 태그와는 독립적으로 만들어져야 한다. 이 객체 자체는 result 애트리뷰트의 값으로서 제공된다.

var 애트리뷰트나 result 애트리뷰트 모두 없다면, 변형 결과는 <x:transform> 액션을 처리한 결과로서 JSP 페이지로 삽입될 것이다. 이는 데이터를 XML에서 HTML로 변형하기 위해 스타일스트가 사용될 때 특히 유용하다. (Listing 3)


Listing 3. JSP 페이지에 변형된 XML 데이터를 직접 디스플레이 하기
				
<c:import var="rssFeed" url="http://slashdot.org/slashdot.rdf"/>
<c:import var="rssToHtml" url="/WEB-INF/xslt/rss2html.xsl"/>
<x:transform xml="${rssFeed}" xslt="${rssToHtml}"/>

이 예제에서, RSS 피드와 스타일시트는 <c:import> 태그를 사용하여 읽힌다. 스타일시트의 아웃풋은 HTML이고, <x:transform>varresult 애트리뷰트를 생략한 채 직접 디스플레이 된다. 그림 1은 결과 샘플이다.


그림 1. Listing 3의 결과
Listing 3의 결과

<x:parse>systemId 애트리뷰트와 마찬가지로, <x:transform>xmlSystemIdxsltSystemId 애트리뷰트는 XML 문서에 상대 경로를 바꾸는데 사용된다. 이 경우, xmlSystemId 애트리뷰트는 태그의 xml 애트리뷰트의 값으로서 제공된 문서에 적용되는 반면, xsltSystemId 애트리뷰트는 태그의 xslt 애트리뷰트에 의해 지정된 스타일시트 내에서 상대 경로를 바꾸는데 사용된다.

문서 변형을 실행하는 스타일시트가 매개변수를 취하면, <x:param> 태그를 사용하여 지정된다. 이 태그가 있다면 <x:transform> 태그의 바디 내에 나타나야 한다. 변형되는 XML 문서 역시 바디 콘텐트로서 지정되면, <x:param> 태그 보다 앞에 나와야 한다.

<x:param> 태그는 본 시리즈 Part 2Part 3에서 설명한 <c:param><fmt:param> 태그와 마찬가지로 두 개의 애트리뷰트, namevalue를 갖고 있다.

XML 콘텐트 작업

파싱과 변형은 전적으로 XML 문서에 대해 실행된다. 문서를 사용 가능한 폼으로 메시지를 보낸 후에, 이 문서에 포함된 데이터의 특정 엘리먼트만이 애플리케이션의 관심의 대상이 될 수가 있다. 이와 같은 이유로, xml 라이브러리에는 XML 문서에서 개별 콘텐트 조각들에 액세스 하여 조작하는 여러 태그들이 포함되어 있다.

본 시리즈의 Part 2(core 분석)을 읽어보았다면, 이러한 xml 태그들의 이름이 낯설지 않을 것이다. 이들은 JSTL의 core 라이브러리의 상응하는 태그들에 기반하고 있다. core 라이브러리 태그는 EL 식을 사용하여 value 애트리뷰트를 통해서 JSP 컨테이너에서 데이터에 액세스 하는 반면, xml 라이브러리의 태그들은 XPath 식을 사용하여 select 애트리뷰트를 통해서 XML 문서에서 데이터에 액세스 한다.

XPath는 XML 문서들의 엘리먼트와 이들의 애트리뷰트와 바디 콘텐트를 참조하는 표준 표기법이다. 이름에서 시사하듯, 이 표기법은 XPath 문이 슬래시로 구분된다는 점에서 파일 시스템 경로와 닮았다. 이러한 컴포넌트들은 XML 문서의 노드로 매핑되고, 연속적인 컴포넌트가 중첩된 엘리먼트와 매칭되며, 별표(asterisks)는 와일드카드로 사용되어 여러 노드들을 매치시키고, 중괄호로 닫힌 식은 애트리뷰트 값을 매치하고 인덱스를 지정하는데 사용될 수 있다. XPath와 사용법을 설명하는 온라인 참조 문서들이 많이 있다. (참고자료).

XML 문서에서 데이터의 엘리먼트를 디스플레이 하려면, <x:out> 액션을 사용하는데, 이것은 core 라이브러리의 <c:out> 태그와 비슷한 것이다. <c:out>에는 valueescapeXml이라는 애트리뷰트가 있는 반면, <x:out>의 애트리뷰트에는 selectescapeXml이 있다.

<x:out select="XPathExpression
" escapeXml="
boolean"/>

물론, 그 차이점은 select 애트리뷰트의 값이 XPath 식이어야 하고, <c:out>value 애트리뷰트는 EL 식이어야 한다는 점이다. escapeXml 애트리뷰트의 의미는 두 태그 모두 같다.

Listing 4는 <x:out> 액션을 묘사하고 있다. select 애트리뷰트용으로 지정된 XPath 식은 SCOPED 변수, 특히 $rss 용 EL 식으로 시작된다. EL 식은 XPath 문이 계산될 파싱 된 XML 문서를 구분한다. 이 문장은 부모 노드의 이름이 channel인, title이라는 이름을 가진 엘리먼트용 문서를 검색하면서, 이것이 찾은 첫 번째 엘리먼트를 선택한다. (이 식의 끝에 [1] 인덱스에 의해 지정됨.) <x:out> 액션은 엘리먼트의 바디 콘텐트가 디스플레이 되도록 하고, XML 문자 이스케이핑을 실행시키지 않는다.


Listing 4. <x:out> 액션을 사용하여 XML 엘리먼트의 바디 콘텐트 디스플레이 하기
				
<c:import var="rssFeed" url="http://slashdot.org/slashdot.rdf"/>
<x:parse var="rss" xml="${rssFeed}"/>

<x:out select="$rss//*[name()='channel']/*[name()='title'][1]" 
  escapeXml="false"/>

<x:out> 외에도, JSTL xml 라이브러리에는 XML 데이터를 조작하는 태그들이 포함되어 있다.

  • <x:set>은 XPath 식의 값을 JSTL 범위가 지정된 변수로 할당한다.
  • <x:if>는 XPath 식의 Boolean 값에 기반하여 콘텐트에 조건을 단다.
  • <x:choose>, <x:when>, <x:otherwise>는 XPath 식에 기반하여 상호 배타적인 조건들을 실행한다.
  • <x:forEach>는 XPath 식에 의해 매칭된 여러 엘리먼트들을 반복한다.

이러한 각각의 태그들은 core 라이브러리의 상응하는 태그와 비슷하게 작동한다. 예를 들어 <x:forEach>의 사용법은 Listing 5에 묘사되어 있는데, <x:forEach> 액션은 RSS 피드를 나타내는 XML 문서에 있는 item이라는 이름을 가진 모든 엘리먼트를 반복한다. <x:forEach>의 바디 콘텐트에 중첩된 두 개의 <x:out>에 있는 XPath 식은 <x:forEach> 태그가 반복하는 노드와 관련이 있다. 이들은 각 item 엘리먼트의 linktitle 자식 노드들을 검색하는데 사용된다.


Listing 5. <x:out>과 <x:forEach> 액션을 사용하여 XML 데이터 선택 및 디스플레이 하기
				
<c:import var="rssFeed" url="http://slashdot.org/slashdot.rdf"/>
<x:parse var="rss" xml="${rssFeed}"/>

<a href="<x:out select="$rss//*[name()='channel']/*[name()='link'][1]"/>"
  ><x:out select="$rss//*[name()='channel']/*[name()='title'][1]" 
    escapeXml="false"/></a>

<x:forEach select="$rss//*[name()='item']">
  <li> <a href="<x:out select="./*[name()='link']"/>"
        ><x:out select="./*[name()='title']" escapeXml="false"/></a>
</x:forEach>

Listing 5의 JSP 코드에서 나온 결과는 그림 1에 나타난 Listing 3의 결과와 동일하다. xml 라이브러리의 XPath 지향 태그는 XML 콘텐트를 변형하는 스타일시트의 좋은 대안이 된다. 특히, 마지막 결과가 HTML일 경우 특히 그렇다.




위로


sql 라이브러리

JSTL 액션의 네 번째 이자 마지막 세트는 sql 커스텀 태그 라이브러리이다. 이름에서 시사하듯, 이 라이브러리는 관계형 데이터베이스들과 상호작용 할 수 있는 태그를 제공한다. 보다 구체적으로 말하면, sql 라이브러리는 데이터소스(datasources)를 지정하고, 쿼리와 업데이트를 실행하고, 쿼리와 업데이트를 트랜잭션으로 그룹핑 하는 태그들을 정의한다.

데이터소스

데이터소스는 데이터베이스 연결을 만드는 팩토리이다. 특정 형태의 커넥션 풀링(connection pooling)을 실행하여 연결을 만들고 초기화 하는 것과 관련한 오버헤드를 최소화 한다. Java 2 Enterprise Edition (J2EE) 애플리케이션 서버는 데이터소스를 지원하는데, Java Naming and Directory Interface (JNDI)를 통해서 J2EE 애플리케이션에 사용할 수 있다.

JSTL의 sql 태그는 연결을 획득할 때 데이터소스에 의존한다. 사실, 많은 것들이 이러한 커넥션 팩토리를 javax.sql.DataSource 인터페이스의 인스턴스나 JNDI 이름으로 지정하는 dataSource 애트리뷰트를 포함하고 있다.

<sql:setDataSource> 태그를 사용하여 javax.sql.DataSource의 인스턴스를 얻을 수 있는데, 다음 두 개의 폼을 취한다.

<sql:setDataSource dataSource="expression"
    var="name
" scope="
scope"/>

<sql:setDataSource url="expression
" driver="
expression"
    user="expression
" password="
expression"
    var="name
" scope="
scope"/>

첫 번째 폼의 경우, dataSource 애트리뷰트만 필요하다. 두 번째의 경우, url 애트리뷰트만 필요하다.

첫 번째 폼을 사용하여 JNDI 이름과 연관된 데이터소스에 액세스 하며, 이에 대한 dataSource 애트리뷰트의 값으로 해당 이름을 제공한다. 두 번째 폼은 새로운 데이터소스가 생성되도록 하며, url 애트리뷰트의 값으로서 제공된 JDBC URL을 사용한다. 선택적인 driver 애트리뷰트는 데이터베이스 드라이버를 실행하는 클래스의 이름을 정하고, userpassword 애트리뷰트는 데이터베이스에 액세스 하는 로그인 권한을 제공한다.

<sql:setDataSource>의 두 폼들은 varscope 애트리뷰트가 지정된 데이터소스를 범위가 지정된 변수로 할당한다. var 애트리뷰트가 없다면, <sql:setDataSource> 액션이 명확한 데이터소스를 지정하지 않는 sql 태그에 의해 사용될 기본 데이터소스를 설정한다.

javax.servlet.jsp.jstl.sql.dataSource 콘텍스트 매개변수를 사용하여 sql 라이브러리의 기본 데이터소스를 설정할 수 있다. 실제로, Listing 6에 있는 것 같은 엔트리를 애플리케이션의 web.xml 파일에 두는 것이 기본 데이터소스를 지정하는 가장 편리한 방법이다. <sql:setDataSource>를 사용하려면 JSP 페이지를 사용하여 애플리케이션을 초기화 하고, 페이지를 자동으로 실행시킬 방법이 필요하다.


Listing 6. JNDI 이름을 사용하여 web.xml 전개 디스크립터에 JSTL의 기본 데이터소스를 설정하기
				
<context-param>
  <param-name>javax.servlet.jsp.jstl.sql.dataSource</param-name>
  <param-value>jdbc/blog</param-value>
</context-param>

쿼리와 업데이트

데이터소스에 액세스 한 후에, <sql:query> 액션을 사용하여 쿼리를 실행할 수 있고, <sql:update> 액션을 사용하여 데이터베이스 업데이트가 실행된다. 쿼리와 업데이트는 SQL 문으로 지정되는데, JDBC의 java.sql.PreparedStatement 인터페이스에 기반한 방식을 사용하여 매개변수화 된다. 매개변수 값은 중첩된 <sql:param><sql:dateParam> 태그를 사용하여 지정된다.

<sql:query> 액션의 세 가지 변수들이 지원된다.

<sql:query sql="expression
" dataSource="
expression" 
    var="name
" scope="
scope"
    maxRows="expression
" startRow="
expression"/>

<sql:query sql="expression
" dataSource="
expression" 
    var="name
" scope="
scope"
    maxRows="expression
" startRow="
expression">
  <sql:param value="expression"/>
  ...
</sql:query>

<sql:query dataSource="expression" 
    var="name
" scope="
scope"
    maxRows="expression
" startRow="
expression">
  SQL statement
  <sql:param value="expression"/>
  ...
</sql:query>

첫 번째 두 폼의 경우, sqlvar 애트리뷰트만 필요하다. 세 번째의 경우 var만 필요하다.

varscope 애트리뷰트는 쿼리 결과를 저장하는 범위가 지정된 변수를 지정한다. maxRows 애트리뷰트는 쿼리에서 리턴 된 행(row)의 수를 제한하는데 사용되고, startRow 애트리뷰트는 일부 초기 행들이 무시되도록 한다. (결과 세트가 데이터베이스에 의해 구성될 때 스킵되는 식이다.)

쿼리를 실행한 후에, 결과 세트는 javax.servlet.jsp.jstl.sql.Result 인터페이스의 인스턴스로서 범위가 지정된 변수에 할당된다. 이 객체는 쿼리의 결과 세트의 행, 칼럼 이름, 크기에 액세스 하는 프로퍼티를 제공한다. 표 1에 요약해 놓았다.

표 1. javax.servlet.jsp.jstl.sql.Result 인터페이스에서 정의한 프로퍼티

프로퍼티 설명
rows SortedMap 객체의 어레이로서, 칼럼 이름을 결과 세트의 행으로 매핑한다.
rowsByIndex 어레이의 어레이이다. 각각 결과 세트의 행과 상응한다.
columnNames 결과 세트에서 칼럼의 이름을 정하는 스트링의 어레이. rowsByIndex 프로퍼티에 사용되었던 것과 같은 순서이다.
rowCount 쿼리 결과에 있는 총 행의 수이다.
limitedByMaxRows maxRows 애트리뷰트의 값에 의해 쿼리가 제한될 경우 true 이다.

이 프로퍼티 중에서, rows는 결과 세트를 반복하고 이름을 사용하여 칼럼 데이터에 액세스 할 수 있기 때문에 특히 편리하다. 이 부분은 Listing 7에 나타나 있는데, 여기에서 쿼리의 결과는 queryResults라고 하는 범위가 지정된 변수로 할당되고, 이 행은 core 라이브러리의 <c:forEach> 태그를 사용하여 반복된다. 중첩된 <c:out> 태그들은 EL의 Map 컬렉션 지원을 활용하여 칼럼 이름에 상응하는 행 데이터를 검색한다. (Part 1을 기억해 보면 알겠지만, ${row.title}${row["title"]}은 동등한 식이었다.)

Listing 7은 데이터소스와 범위가 지정된 변수를 연결하는 <sql:setDataSource>의 사용 모습이다. 이것은 dataSource 애트리뷰트를 통해서 <sql:query> 액션에 의해 액세스 된다.


Listing 7. <sql:query>를 사용하여 데이터베이스에 쿼리하고, <c:forEach>를 사용하여 결과 세트를 반복하기
				
<sql:setDataSource var="dataSrc"
    url="jdbc:mysql:///taglib" driver="org.gjt.mm.mysql.Driver"
    user="admin" password="secret"/>
    <sql:query var="queryResults" dataSource="${dataSrc}">
  select * from blog group by created desc limit ?
  <sql:param value="${6}"/>
</sql:query>

<table border="1">
  <tr>
    <th>ID</th>
    <th>Created</th>
    <th>Title</th>
    <th>Author</th>
  </tr>
<c:forEach var="row" items="${queryResults.rows}">
  <tr>
    <td><c:out value="${row.id}"/></td>
    <td><c:out value="${row.created}"/></td>
    <td><c:out value="${row.title}"/></td>
    <td><c:out value="${row.author}"/></td>
  </tr>
</c:forEach>
</table>

그림 2는 Listing 7의 JSTL 코드에 상응하는 페이지 결과 모습이다. Listing 7의 <sql:query> 액션의 바디에 나타난 SQL 문은 매개변수화 된다.


그림 2. Listing 7의 결과
Listing 7의 결과

<sql:query> 액션에서, 바디 콘텐트로서 또는 sql 애트리뷰트를 통해 지정된 SQL 문은 ? 문자를 사용하여 매개변수화 된다. SQL 문의 이 같은 매개변수의 경우, <sql:query> 태그의 바디에 중첩돼 상응하는 <sql:param> 또는 <sql:dateParam> 액션이 있어야 한다. <sql:param> 태그는 매개변수 값을 지정하는 하나의 애트리뷰트인 value를 취한다. 이 매개변수의 값이 문자 스트링일 때, value 애트리뷰트를 생략하고 <sql:param> 태그의 바디 콘텐트로서 매개변수 값을 제공할 수 있다.

날짜, 시간, 타임 스탬프를 나타내는 매개변수 값은 <sql:dateParam> 태그를 사용하여 지정되고, 다음과 같은 문법을 사용한다.

<sql:dateParam value="expression
" type="
type"/>

<sql:dateParam>의 경우, value 애트리뷰트에 대한 식은 java.util.Date 클래스의 인스턴스를 계산해야 하고, type 애트리뷰트의 값은 SQL 문에 어떤 것이 필요한지에 따라서, date, time, 또는 timestamp 중 하나가 되어야 한다.

<sql:query>와 마찬가지로, <sql:update> 액션도 세 가지 폼을 지원한다.

<sql:update sql="expression
" dataSource="
expression" 
    var="name
" scope="
scope"/>

<sql:update sql="expression
" dataSource="
expression" 
    var="name
" scope="
scope">
  <sql:param value="expression"/>
  ...
</sql:update>

<sql:update dataSource="expression" 
    var="name
" scope="
scope">
  SQL statement
  <sql:param value="expression"/>
  ...
</sql:update>

sqldataSource 애트리뷰트는 <sql:update>에도 <sql:query>와 같은 의미를 지닌다. 마찬가지로, varscope 애트리뷰트가 범위가 지정된 변수를 지정하지만, 이 경우 범위가 지정된 변수로 할당된 값은 java.lang.Integer이 인스턴스이고, 데이터베이스 업데이트를 실행한 결과로 변경된 행들의 수를 나타낸다.

트랜잭션 관리하기

트랜잭션은 하나의 작업 그룹으로서 성공 또는 실패 시에 데이터베이스 연산 결과를 보호하는데 사용된다. 트랜잭션은 JSTL의 sql 라이브러리에서 지원되며, 상응하는 <sql:query><sql:update> 액션들을 <sql:transaction> 태그의 바디 콘텐트에 중첩하는 것으로써 트랜잭션으로 쉽게 래핑한다.

<sql:transaction>의 문법은 다음과 같다.

<sql:transaction dataSource="expression
" isolation="
isolationLevel">
  <sql:query .../> or  <sql:update .../>
  ...

<sql:transaction> 액션에는 필요한 애트리뷰트가 없다. dataSource 애트리뷰트를 생략하면, JSTL의 기본 데이터소스가 사용된다. isolation 애트리뷰트는 트랜잭션의 고립 레벨(isolation level)을 지정하고, read_committed, read_uncommitted, repeatable_read, serializable 중 하나가 된다. 이 애트리뷰트를 지정하지 않으면, 트랜잭션은 데이터소스의 디폴트(default)의 고립 레벨을 사용할 것이다.

여러분도 예상했겠지만, 모든 중첩된 쿼리와 업데이트는 트랜잭션과 같은 데이터소스를 사용한다. 사실, <sql:transaction> 액션 내에 중첩된 <sql:query><sql:update>dataSource 애트리뷰트를 지정할 수 없다. 주변 <sql:transaction> 태그와 제휴된 데이터소스를 자동으로 사용하게 될 것이다.

Listing 8은 <sql:transaction>이 사용되는 모습이다.


Listing 8. <sql:transaction>을 사용하여 데이터베이스 업데이트를 트랜잭션에 결합하기
				
<sql:transaction>
  <sql:update sql="update blog set title = ? where id = ?">
    <sql:param value="New Title"/>
    <sql:param value="${23}"/>
  </sql:update>
  <sql:update sql="update blog set last_modified = now() where id = ?">
    <sql:param value="${23}"/>
  </sql:update>
</sql:transaction>




위로


주의

JSTL의 xmlsql 라이브러리는 커스텀 태그들을 사용하여 JSP 페이지에서 복잡한 기능들이 실행될 수 있도록 한다. 하지만, 프리젠테이션 레이어에서 이러한 기능을 실행하는 것은 그렇게 좋은 방법은 아니다.

여러 개발자들이 오랜 기간 동안 개발한 대형 애플리케이션의 경우, 사용자 인터페이스, 기반 비즈니스 로직, 데이터 저장소를 엄격히 분리하면 오랜 기간 동안 소프트웨어 관리를 단순화 할 수 있다. 유명한 Model-View-Controller (MVC) 디자인 패턴은 이 "베스트 프랙티스" 전형이다. J2EE 웹 애플리케이션에서, 모델은 애플리케이션의 비즈니스 로직이고, 프리젠테이션 레이어를 구성하는 JSP 페이지들은 뷰가 된다. (컨트롤러는 모델을 수정하고 뷰를 업데이트 하는 브라우저 액션을 실행하는 서버 측 메커니즘과 폼 핸들러이다.) MVC는 애플리케이션의 세 가지 주요 요소들-모델, 뷰, 컨트롤러-이 서로 최소한의 의존성을 갖도록 하며, 이들의 인터랙션도 일관성 있는, 정의가 잘 된 인터페이스로 제한한다.

데이터 교환에는 XML 문서를 이용하고, 데이터 영속성에는 관계형 데이터베이스를 의존하는 것이 애플리케이션의 비즈니스 로직(모델)의 특성이다. 따라서, MVC 디자인 패턴은 상세한 실행 내역들이 애플리케이션의 프리젠테이션 레이어(뷰)에 반영되지 않도록 하고 있다. JSP가 프리젠테이션 레이어를 실행할 때 사용된다면, xmlsql 라이브러리를 사용하는 것이 MVC를 위반하는 것이 된다. 왜냐하면 프리젠테이션 레이어 내에 기반 비즈니스 로직의 엘리먼트를 노출하는 것을 의미하기 때문이다.

이 같은 이유로, xmlsql 라이브러리는 작은 프로젝트와 프로토타이핑에 가장 잘 맞는다. 애플리케이션 서버에 의한 JSP 페이지의 동적 컴파일 역시 디버깅 툴로서 커스텀 태그들이 유용하다.




위로


요약

소셜 북마크

mar.gar.in mar.gar.in
digg Digg
del.icio.us del.icio.us
Slashdot Slashdot

본 시리즈에서, 네 가지 JSTL 커스텀 태그 라이브러리의 기능과 사용법을 설명했다. Part 1Part 2에서는 EL과 core 라이브러리의 태그를 사용하여 JSP 스크립팅 엘리먼트를 피하는 방법을 설명했고, Part 3에서는 웹 콘텐트를 로컬화 하는 fmt 라이브러리에 대해 집중 설명했다.

이번 마지막 기술자료에서는, xmlsql 라이브러리의 기능을 살펴보았다. 프리젠테이션 레이어에 비즈니스 로직을 추가했을 때 나타나는 결과를 참을 수만 있다면, 이 두 개의 라이브러리에 있는 태그들은 XML 문서와 관계형 데이터베이스의 콘텐트를 JSP 페이지로 매우 쉽게 결합할 수 있도록 한다. 이 두 개의 라이브러리를 통해 <sql:query><c:forEach>를 통합할 때 JSTL 라이브러리가 구현되고 상호 작동한다는 것과 xml 라이브러리가 <c:import> 액션을 활용하는 기능이 있다는 것도 알 수 있었다.

기사의 원문보기





위로


다운로드 하십시오

이름 크기 다운로드 방식
j-jstl0520.jar  FTP
다운로드 방식에 대한 정보


참고자료



필자소개

Mark Kolb은 소프트웨어 엔지니어이다. 서버 측 자바 플랫폼을 주제로 많은 강연을 하고 있으며, Web Development with JavaServer Pages, 2nd Edition 의 공동 저자이다. (mailto:mak@taglib.com?cc=)



관련글 더보기