관리 메뉴

I LOVE EJ

JSTL 정리문서 본문

Web Development/JSP

JSTL 정리문서

BeOne 2008. 4. 4. 11:44
JSTL (JSP Standard Tag Library)

 

1           JSTL 개요

1.1          JSTL 이란

커스텀태그를 공부하면서 jsp페이지에서 자바코드를 추출하는데 탁월한 성능을 발휘하는 모습을 보았다. 허나 이것을 만든다고 생각하면, 아직도 좀 아찔한 감이 남아있다. 개발시간은 촉박한데, 로직 부분을 빼낸다고, tld 만들고, 태그핸들러 만들고, 컴파일하고, 잘 동작하는지 테스트해보고 하려면 사실 시간이 더 많이 소요되기 때문에 망설여지는 것이 사실이다.

하지만 커스텀태그 소개하면서 계속 얘기했던 것은 자주 쓰이는 커스텀태그들을 표준으로 정해서 모아놓은 것이 있으니까, 이것들만 잘 찾아서 쓰면 된다고 얘기했다. 정말 알짜들만 모아놓았다. 최정예 커스텀태그들을 모아서 이름을 붙여준 것이 JSP Stadard Tag Library 이고, 줄여서 JSTL 이라고 부른다. JCP(http://www.jcp.org )에서 표준을 제정했다. JSR-52 에서 각계의 전문가들이 심사 후에 알짜들을 모아놓은 것이다.

 

1.2          JSTL 현황

집필하는 현재 JSTL JSP2.0 스펙에 포함되었다. 따라서 JSP2.0 의 표준을 제일 먼저 구현해서 참고를 삼는 톰캣5.0 이 정식으로 발표된다면, 별다른 설치를 하지 않고 바로 JSTL을 사용할 수 있게 된다. (이미 발표된 톰캣5.0 알파버전에는 JSTL의 기능은 빠져 있다. EL 과 심플 커스텀태그와 태그파일의 기능은 들어가 있고, JSTL JSF는 빠져있다.)

JSTL EL 을 이용해서 객체의 접근을 쉽게 할 수 있다. jsp 에서 객체의 접근은 먼저 선언부터 되어야 되지만, EL에서는 별다른 선언없이도 객체를 받아서 처리할 수 있게 되었다. 이에 관해서는 후에 예제를 통해서 살펴보겠다.

JSTL 에 관련된 최신 정보는 sun jstl 홈페이지 http://java.sun.com/products/jsp/jstl 와 자카르타 프로젝트의 taglibs http://jakarta.apache.org/taglibs 를 통해서 얻을 수 있다.

 

1.3          JSTL 처리영역

JSTL은 태생이 커스텀태그이기 때문에 jsp와 밀접하게 관계가 있다. application, session, request, response, pageContext 등의 내장객체에 쉽게 접근하며, 그 외에도 파라메터, 헤더, 쿠키 등을 복잡한 코드를 사용하지않고, 쉽게 직관적으로 사용할 수 있다. 또한 기본적인 연산이나 객체의 비교 등을 .equals() 메소드 등을 이용하는 대신 == 와 같이 쉽게 구현했으며, 조건, 반복, 이동에 대한 태그를 지원하기 때문에 태그만으로도 반복 기능을 구현할 수 있다.

JSTL 의 처리영역은 크게 4가지로 나누어진다. core, format, xml, sql 로 기능이 구분되고, 각각의 기능은 이름이 말해 주듯, 기본기능, 형식화, xml처리, sql처리를 담당한다.

기능

prefix

기본URI

기본기능

c

http://java.sun.com/jstl/core

XML 처리

x

http://java.sun.com/jstl/xml

i18n & 형식화

fmt

http://java.sun.com/jstl/fmt

데이터베이스 작업

sql

http://java.sun.com/jstl/sql

 

2           JSTL 설치

2.1          JSTL 다운로드

JSTL JSP2.0 표준 스펙에 포함이 되었지만 아직 이 스펙을 지원하는 제품이 나오지 않은 상태이기 때문에 기존의 톰캣4에서 사용할 수 있게 설치하는 법을 알아보려고 한다.

이 책의 논외가 되겠지만 sun에서 나온 JWSDP(Java Web Services Developer Pack)에는 톰캣4.1.2 JSTL v1.0.3 이 기본으로 들어있기 때문에 이것만 설치하면 쉽게 JSTL을 사용할 수 있다. 이에 관한 사용법은 다음 주소를 참고하기 바란다. http://java.sun.com/webservices/docs/1.1/tutorial/doc/index.html 

jstl의 기본 설명도 충실하게 잘 나와있고, 웹서비스에 관련된 좋은 안내서이기에 꼭 읽어보기 바란다.

JSTL은 현재 자카르타의 taglibs 서브 프로젝트에서 받아올 수 있다.  http://jakarta.apache.org/taglibs 에 접속하고, Downloads 링크를 클릭한다. Release 버전과 Nightly Build 버전이 있는데, 정식 릴리스 버전은 현재 1.0.3 까지 나와있다.

http://www.apache.org/dist/jakarta/taglibs/standard/ 에 가면 바이너리 빌드를 받아 볼 수 있다. jakarta-taglibs-standard-current.zip 를 다운로드 받아서 적당한 위치에 압축을 푼다.

 

2.2          JSTL 예제 설치

jakarta-taglibs 디렉토리 아래 standard 에서 standard-examples.war 파일을 jstl.war 파일로 이름을 바꾼 뒤에 Tomcat 4 가 설치된 디렉토리의 webapps 디렉토리에 복사한다.

server.xml <Host> unpackWARs="true" 로 설정되어 있다면, jstl 이라는 디렉토리가 자동으로 생기면서 jstl.war 의 압축이 풀린 뒤에 브라우저에서 http://localhost:포트/jstl 로 예제 웹 어플리케이션을 실행해 볼 수 있다.

 

2.3          JSTL add-on 설치

기존의 컨텍스트에서 JSTL을 사용하기 위해서는 웹 어플리케이션의 WEB-INF/lib 디렉토리에 필요한 라이브러리를 복사하면 된다. JSTL 의 주된 라이브러리 파일은 jstl.jar, standard.jar 이고, xml에서 지원되는 기능을 사용하기 위해서 jaxen-full.jar, saxpath.jar,  jaxp-api.jar 파일 등이 필요하다. 이 파일들을 웹어플리케이션의 WEB-INF/lib 에 복사하고, 컨텍스트를 리로드한다. 구체적인 파일들의 명세는 다음과 같다.

이름

설명

파일

JSTL 1.0 API 클래스

jstl 1.0 API 클래스

jstl.jar

JSTL 1.0 구현 클래스

JSTL 구현

standard.jar

Jaxen 1.0

Xpath 엔진

jaxen-full.jar

Saxpath 1.0

Xpath 파싱에 필요 sax 방식

saxpath.jar

Jdbc 2.0 선택 패키지

JDBC 구현 클래스
j2se1.4,
톰캣4 기본포함

jdbc2_0-stdext.jar

Jaxp 1.2 구현

jaxp 1.2 호환 파서 필요

jaxp-api.jar
dom.jar
sax.jar
xercesImpl.jar

Xalan

아파치 xslt 변환기

xalan.jar

만일 톰캣4 ROOT 컨텍스트에 설치를 한 경우에는 webapps/ROOT/WEB-INF/ 아래에 lib 디렉토리를 만들고 jstl 의 필요한 JAR 파일들을 복사해 놓으면 된다.

 

2.4          JSTL tld 파일

tld파일이 없거나, web.xml 파일에 8개의 tld 파일을 등록하지 않아도 표준태그는 사용할 수 있도록 되어 있다.

4가지의 JSTL 태그마다 EL 기반과 RT 기반의 태그로 나눠진다. 태그핸들러의 종류는 똑같지만 차이가 있다면 value 값으로 EL 을 사용하느냐 아니면 스크립트의 표현식을 허용하느냐의 차이다. 이에 관해서는 후에 살펴보겠다.

서버에 따라서 필요한 경우가 있으므로 간략히 방법을 설명하면, jakarta-taglibs standard 디렉토리에 있는 tld 디렉토리의 8개의 tld 파일을 웹 어플리케이션의 WEB-INF/ 아래에 적당한 위치에 복사한 뒤에 이 파일들의 위치를 web.xml 에 등록한다.

 

3           표현언어 EL (Expression Language)

EL은 다양한 위치에 있는 데이터에 접근하기 위한 언어이다. 문법체계가 직관적으로 아주 쉽다. jsp 에서는 모든 변수의 생성과 선언을 반드시 표시를 해주어야 되지만 EL은 그 과정 없이 바로 접근이 가능하다.

 

3.1          EL 표시형식

EL임을 표시하는 형식은 ${} 이다. 이 안에 들어있는 것은 EL 로 처리된다. 내장객체의 접근이 가능하고, 산술연산과 비교연산이 가능하다.

자바스크립트와 비슷한 방법으로 객체 내부의 자원에 접근이 가능하다. dot(.) bracket([]) 모두를 이용해서 접근할 수 있으며, 예를 들면

${header.cookie} ${header['cookie']} 는 같은 결과 값을 얻을 수 있다. 만일 user-agent 처럼 - 와 같이 있을 경우는 ${header['user-agent']} 로 접근하는 것이 좋다.

[] 를 이용해서 객체에 접근할 경우에 index 를 대신해서 사용할 수도 있다.

다음 예제는 이전 내용을 요약한 것이다.

예제 1.   jstlel01.jsp

<% response.setContentType("text/html;"); %>

<%@ taglib prefix="c" uri="http://java.sun.com/jstl/core" %>

<h3>header</h3>

<c:forEach items="${header}" var="h">

  <c:out value="${h}"/><br/>

</c:forEach>

<h3>header.cookie</h3>

<c:out value="${header.cookie}"/><br/>

<c:out value='${header["cookie"]}'/>

 

 

header 라는 객체가 갖고 있는 값들을 불러서 보여주는 소스이다. request.getHeader() 로 가져올 수 있는 것인데, 훨씬 깔끔한 소스로 보여진다.

JSTL 태그에서 기본적으로 EL을 사용한다. var 속성은 변수를 지정하는데, 여기에는 문자열 상수로 지정되며, 이 후에 이 변수를 참조하기 위해서는 EL 을 사용한다.

 

3.2          EL 내장객체

EL 로 접근할 수 있는 내장 객체들은 다음과 같다.

pageScope

page scope 의 변수들

requestScope

request scope 의 변수들

sessionScope

session scope 의 변수들

applicationScope

application scope 의 변수들

param

parameter 변수들 문자열

paramValues

parameter 변수들 문자열 배열

header

HTTP request 헤더

headerValues

HTTP request 헤더 문자열 배열

initParam

컨텍스트 초기 변수 web.xml 에서 지정

cookie

쿠키 변수들

pageContext

현재 페이지의 pageContext 객체

 

pageScope 의 변수는 스크립틀릿의 변수와는 틀리며, 이를 이용하려면 조금은 번잡한 과정을 거치게 된다. 따라서 가능하면 스크립틀릿은 사용하지 않기를 권장한다. 이를 활용하는 소스이다.

예제 2.   jstlel02.jsp

<% response.setContentType("text/html;"); %>

<%@ taglib prefix="c" uri="http://java.sun.com/jstl/core" %>

<%@ taglib prefix="c_rt" uri="http://java.sun.com/jstl/core_rt" %>

<% String[] abc = {"빨강","파랑","노랑"}; %>

 

<c:set var="t" value="hello"/>

<c_rt:set var="color" value="<%=abc%>"/>

 

<h3>pageScope</h3>

<c:forEach items="${pageScope}" var="h">

    <c:out value="${h}"/><br/>

</c:forEach>

 

<h3>colors</h3>

<c:forEach items="${color}" varStatus="i">

    <c:out value="${i.count}"/>.

    <c:out value="${color[i.index]}"/><br/>

</c:forEach>

 

 

<c:forEach/> 를 통해서 pageScope 의 값을 모두 출력해보면, String 배열변수인 abc 는 접근할 수 없게 되어있다. <c:set/> <c_rt:set/> 으로 정해놓은 t color 만 나타나는 것이 보인다.

color 의 값을 출력하는 코드를 보면 color 의 인덱스를 이용해 배열 내용을 뽑아 왔다. varStatus 대신 var 변수를 통해서 바로 내용을 출력할 수도 있다.

 

value 가 들어가는 자리에 표현식을 쓰기 위해서는 RT 기반의 태그를 사용해야 된다. 만일 <c_rt:set var="color" value="<%=abc%>"/> 에서 <c_rt:set/> 대신 <c:set/> 를 사용하면 color 가 갖게 되는 값은 "<%=abc%>" 문자열이 되어버린다.

 

3.3          EL 연산자

null 인지 아닌지 판단하기 위해서는 empty 라는 키워드를 사용한다. 세션 값이 없으면 세션에 값을 저장하고, 있을 경우 하나를 더한 후에 출력하는 코드이다

예제 3.   jstlel03.jsp

<% response.setContentType("text/html;"); %>

<%@ taglib prefix="c" uri="http://java.sun.com/jstl/core" %>

<c:if test="${!empty hit}">

    <c:set var="hit" value="${hit+1}" scope="session"/>

    <c:out value="${hit}"/> 번 리로드되었습니다.

</c:if>

<c:if test="${empty hit}">

    <c:set var="hit" value="1" scope="session"/>

    세션에 값을 저장했습니다.

</c:if>

<br>

<a href="jstlel03.jsp">reload</a>

 

 

EL 의 장점은 객체의 접근이 쉽다고 했다. ${empty 객체} 를 통해서, 객체의 null 을 확인할 수 있다. ${!empty hit} ${!empty sessionScope.hit} 로 대치해도 같은 결과가 나온다.

EL 의 연산자는 관계연산자, 산술연산자, 논리연산자, empty 연산자가 있고 다음 표와 같다.

연산자 구분

연산자

관계

< lt > gt <= le >= ge == eq != ne

산술

+ - * / div % mod

논리

&& and || or ! not

Empty

empty

 

연산자들간의 우선순위는 다음과 같다.

1. [] .

2. ()

3. - (단항) not ! empty

4. * / div % mod

5. + - (이항)

6. < > <= >= lt gt le ge

7. == != eq ne

8. && and

9. || or

 

4           JSTL Core

core 태그를 사용하기 위해서 페이지 상단에 다음과 같이 선언되어야 된다.

<%@ taglib uri="http://java.sun.com/jstl/core" prefix="c"%>

가장 빈번하고 자주 쓰이는 것이다. Core 의 태그들은 다음과 같이 정리된다.

기능

태그

prefix

EL 지원

catch , out , remove , set

c

흐름 제어

choose (when , otherwise) , forEach , forTokens , if

URL 관리

Import (param) , redirect (param) , url (param)

 

4.1          <c:out/>

가장 많이 쓰게 되는 것은 JSP 의 표현식을 대체하는 <c:out/> 이다. 다음과 같은 형식을 갖고 있다.

body 없는 경우

<c:out value="value" [escapeXml="{true|false}"] [default="기본값"] />

 

body 있는 경우

<c:out value="value" [escapeXml="{true|false}"] />

기본값

</c:out>

 

 

[] 으로 둘러 쌓인 부분은 생략 가능한 부분이다. value default 값은 일반 문자열이나 EL 이 들어간다. value 안에 JSP의 표현식을 사용하려 한다면 RT 기반의 <c_rt:out> 을 사용해야 된다는 것은 이전 예제에서 살펴 보았다.

escapeXml 속성은 값 중에 포함된 < > & ' " 문자들을 각각 &lt; &gt; &amp; &#039; &#034; 로 출력한다. 생략될 경우 true 가 기본 값이다.

null 값의 처리에 대해서 JSP expression 의 경우는 "null" 문자열로 출력이 되었던 것을 jstl의 스펙에서는 이 경우 빈 문자열("")또는 기본값으로 처리한다고 명시되어있다.

 

4.2          <c:set/>, <c:remove/>

<c:set/> 의 기본형식은 다음과 같다. scope 속성이 생략될 경우 기본값은 page 이다.

Syntax 1: scope 에 해당하는 변수에 속성 값을 정한다.

<c:set value="value"

var="varName" [scope="{page|request|session|application}"]/>

 

Syntax 2: scope 에 해당하는 변수에 body 값을 정한다.

<c:set var="varName" [scope="{page|request|session|application}"]>

body content

</c:set>

 

Syntax 3: 속성 값으로 target 객체의 프로퍼티 값을 정한다.

<c:set value="value"

target="target" property="propertyName"/>

 

Syntax 4: body 값으로 target 객체의 프로퍼티 값을 정한다.

<c:set target="target" property="propertyName">

body content

</c:set>

 

변수에 값을 할당한다. 빈과 같은 객체에 할당하기 위해서는 target property속성을 이용한다.

 

<c:remove/> JSP removeAttribute() 와 같은 역할을 한다. 해당 scope 에 있는 변수를 제거하는 역할을 한다.

 

4.3          <c:catch/>

<c:catch/> body 위치에서 실행되는 코드의 예외를 잡아내는 역할을 담당한다. var 속성을 지정해서 변수를 선언하면 그 변수에 예외의 내용이 들어가게 된다.

 

다음 예제는 이상의 태그를 사용한 예제이다.

예제 4.   jstlcore01.jsp

<% response.setContentType("text/html"); %>

<%@ taglib uri="http://java.sun.com/jstl/core" prefix="c" %>

<h3>코어 </h3>

<h4>&lt;c:out></h4>

<pre>

${1+2} <c:out value="${1+2}"/>

${1>3} <c:out value="${1>3}"/>

${1 gt 3} <c:out value="${1 gt 3}"/>

 

${ 표시 <c:out value="${'${'}test}"/>

 

escapeXml 속성; 기본값은 false

false: <c:out value="<b>bold</b> <,>,&,',\" " escapeXml="false"/>

true:  <c:out value="<b>bold</b> <,>,&,',\" " escapeXml="true"/>

 

" 큰따옴표 사용주의; ' 작은따옴표로 대치

&lt;c:out value='&lt;font color="blue">파랑&lt;/font>'/>

<c:out value='<font color="blue">파랑</font>' escapeXml="false"/>

 

<hr><h4>&lt;c:set></h4>

set session scope var "name": <c:set var="name" value="하늘" scope="session"/>

c:out name: <c:out value="${name}"/>

expression name: <%= session.getAttribute("name")%>

 

set page scope var "name": <c:set var="name">

  hello

</c:set>

c:out name: <c:out value="${pageScope.name}"/>

c:out sessionScope.name: <c:out value="${sessionScope.name}"/>

expression name: <%= session.getAttribute("name")%>

 

<hr><h4>&lt;c:remove></h4>

remove session scope var "name": <c:remove var="name" scope="session"/>

expression name: <%= session.getAttribute("name")%>

c:out sessionScope.name: <c:out value="${sessionScope.name}"/>

 

<hr><h4>&lt;c:catch></h4>

<c:catch var="errmsg">

line1

<%=1/0 %>

line2

</c:catch>

<c:out value="${errmsg}"/>

</pre>

 

 

value 속성에 들어가는 값은 문자열과 EL 이다. EL의 경우 ${} 안에서 나온 결과값을 표시한다. 부등호 > gt 는 같은 뜻이다. "${" 를 표시하기 위해서는 EL 로 감싸야 된다. ${'${'} 로 해야 표시된다.

escapeXml 속성은 브라우저에서 특수한 기능을 하는 문자 표시 여부를 결정한다. false 값일 경우는 태그가 먹힌 굵은 글씨의 bold 가 나오고, true 일 경우는 '<' '>'를 각각 '&lt;','&gt;' 로 변환한다. 결과는 <b>bold</b> , 브라우저에서 태그가 보이도록 나온다.

큰따옴표와 작은따옴표는 바꿔서 쓸 수 있다. 대신 짝이 맞아야 된다. 또한 하나로 다 이어서 쓸 경우 변환과정에서 에러가 나기 때문에 주의해야된다.

따옴표 사용 예

외부

문자열내부

사용

<c:out value='<font color="blue">파랑</font>' />

작은

가능

<c:out value="<font color='blue'>파랑</font>" />

작은

가능

<c:out value="<font color="blue">파랑</font>" />

불가

session 스코프에 name 이라는 key "하늘"을 넣는다. <c:out value="${name}"/> 으로 scope 를 지정하지 않아도 내장 객체를 훑어서 sessionScope에서 걸리는 "name"키를 찾아서 출력한다. 이 값은 스크립틀릿에서도 참고할 수 있다.

page 스코프에 같은 key "hello" 라는 값을 넣으면 <c:out value="${name}"/> 은 더 이상 session 에 있는 값을 가져오지 않는다.

<c:remove/> 를 통해서 scope 속성에 지정된 key 값을 제거한다.

 

예제에서 <c:catch/> 태그는 body 실행 도중에 <%=1/0 %> 에서 예외가 발생한 것을 errmsg 라는 변수에 넣는다. 이 후에 <c:out/> 을 통해서 에러 메시지를 표시한다.

 

4.4          <c:if/>

<c:if/> 는 흔히 보는 조건문이다. 형식은 다음과 같다.

Syntax 1: Body 없는 경우

<c:if test="testCondition"

var="varName" [scope="{page|request|session|application}"]/>

 

Syntax 2: Body 있는 경우

<c:if test="testCondition"

[var="varName"] [scope="{page|request|session|application}"]>

body content

</c:if>

 

 

<c:if/> 에서 나온 결과를 varName 변수에 넣고, 나중에 활용이 가능하다. 변수의 scope는 임의로 지정할 수 있고, 생략될 경우 기본값은 page 이다.

 

4.5          <c:choose/>, <c:when/>, <c:otherwise/>

<c:choose/> 태그는 java switch 문과 같지만, 조건에 문자열 비교도 가능하고 쓰임의 범위가 넓다. 또한 <c:if/> 태그에 else 가 없기 때문에 이의 대체 기능도 수행한다.

형식은 다음과 같다.

<c:choose>

body content

(하나 이상의 <when> 과 하나 이하의 <otherwise> 서브태그)

    <c:when test="조건">

        body content

    </c:when>

   

    <c:otherwise>

        conditional block

    </c:otherwise>

</c:choose>

 

조건 판단을 수행하는 간단한 예제이다.

예제 5.   jstlcore02.jsp

<% response.setContentType("text/html"); %>

<%@ taglib uri="http://java.sun.com/jstl/core" prefix="c"%>

<h3>조건</h3>

파라메터 없음:<c:out value="${empty param.name}" />

<h4>&lt;c:if test=""></h4>

<c:if test="${empty param.name}">

<form>

이름을 적어주세요.<br>

    <input type="text" name="name">

    <input type="submit" value="확인">

</form>

</c:if>

<c:if test="${!empty param.name}">

    안녕하세요. <c:out value="${param.name}"/>.

</c:if>

 

<h4>&lt;c:choose> &ltc:when test=""> &ltc:otherwise></h4>

<c:choose>

    <c:when test="${empty param.name}">

        <form>

        이름을 적어주세요.<br>

            <input type="text" name="name">

            <input type="submit" value="확인">

        </form>

    </c:when>

    <c:when test="${param.name=='admin'}">

        안녕하세요. 관리자님.

    </c:when>

    <c:otherwise>

        안녕하세요. <c:out value="${param.name}"/>.

    </c:otherwise>

</c:choose>

파라메터 name 값이 없는 경우 입력 폼을 출력한다. 파라메터 name 의 값이 "admin"일 경우 관리자를 표시하고, 그 외에는 파라메터 값을 그대로 출력한다.

파라메터의 유무는 empty !empty 연산자를 통해서 확인할 수 있다.

 

4.6          <c:forEach/>, <c:forTokens/>

<c:forEach/> 는 강력한 반복실행 태그이다. 형식은 다음과 같다.

Syntax 1: 객체 전체에 걸쳐서 반복

<c:forEach [var="varName"] items="collection"

           [varStatus="varStatusName"]

           [begin="begin"] [end="end"] [step="step"]>

    body content

</c:forEach>

 

Syntax 2: 지정한 횟수만큼 반복

<c:forEach [var="varName"]

           [varStatus="varStatusName"]

           begin="begin" end="end" [step="step"]>

    body content

</c:forEach>

 

<c:forEach/> 태그는 여러가지로 활용이 가능하다. 원하는 구간만큼 반복할 수도 있고, 객체를 받아와서 그 객체의 길이만큼 반복할 수도 있다. begin , end 속성은 시작번호와 끝번호를 지정하고, step 속성을 이용해서 증가 구간을 정할 수 있다. var 속성에서 정한 변수로 반복되는 내부 구간에서 사용할 수 있다.

 

<c:forTokens/> java.util.StringTokenizer 를 이용한 것이다. 형식은 다음과 같다.

Syntax

<c:forTokens items="stringOfTokens" delims="delimiters"

[var="varName"]

[varStatus="varStatusName"]

[begin="begin"] [end="end"] [step="step"]>

body content

</c:forEach>

 

<c:forEach/> <c:forTokens/> 를 활용한 예제이다.

예제 6.   jstlcore03.jsp

<% response.setContentType("text/html"); %>

<%@ taglib uri="http://java.sun.com/jstl/core" prefix="c"%>

<h3>반복</h3>

<h4>&lt;c:forEach></h4>

 

<c:forEach var="one" begin="1" end="10">

    <c:out value="${one}"/>

</c:forEach>

<p><b>header</b></p>

<c:forEach var="h" items="${header}">

    <c:out value="${h.key}:${h.value}"/><br>

</c:forEach>

 

<h4>&lt;c:forTokens></h4>

<c:forTokens var="one"

            items="서울|인천,대전,대구,부산,광주,평양"

            delims="," varStatus="sts">

    <c:out value="${sts.count}:${one}"/>&middot;

</c:forTokens>

<hr>

<c:forTokens var="one"

            items="서울|인천,대전,대구,부산,광주,평양"

            delims=",|" varStatus="sts">

    <c:out value="${sts.count}:${one}"/>&#149;

</c:forTokens>

 

예제의 첫번째 <c:forEach/> 에서는 1에서 10까지 반복하면서 값을 출력한다. 이때 var속성의 one변수에는 진행중인 값이 저장된다.

두번째 <c:forEach/> 반복문을 보면 items 속성에 header 객체를 받아온다. header 객체는 Map 형태이고, getKey() getValue() 메소드의 사용이 가능하기 때문에 h.key h.value 를 통해서 출력할 수 있다.

<c:forTokens/> 태그는 StringTokenizer 와 동일한 기능을 한다. delims 속성에 정해진 char 로 나뉘어지게 된다. 마지막 반복구간에서 마디로 나누는 기준은 , | 두 가지이다.

varStatus 속성에서 정해준 변수는 .index .count 를 사용할 수 있고, 시작 번호는 각각 0 1 이다.

 

4.7          <c:import/>

이제 소개할 <c:import/> 는 아주 강력한 도구이다. 웹 어플리케이션 내부의 자원 접근은 물론이고, http, ftp 같은 외부에 있는 자원도 가져와서 페이지 내에 귀속시킨다. 자유롭게 가공할 수도 있고, 편집도 가능하다. <c:import/> 의 형식은 다음과 같다.

Syntax 1: 해당 주소를 바로 출력하거나 String 에 담아놓는다.

<c:import url="url" [context="context"]

        [var="varName"] [scope="{page|request|session|application}"]

        [charEncoding="charEncoding"]>

   <c:param> 서브 태그 위치

</c:import>

 

Syntax 2: 해당 주소의 컨텐츠를 Reader 객체로

<c:import url="url" [context="context"]

        varReader="varReaderName"

        [charEncoding="charEncoding"]>

    varReader 를 사용하는 액션

</c:import>

스트림으로 받아와서 파일로 저장하거나, DB에 입력할 수도 있도록 되어있다.

다음은 간단한 예제이다.

예제 7.   jstlcore04.jsp

<% response.setContentType("text/html"); %>

<%@ taglib uri="http://java.sun.com/jstl/core" prefix="c"%>

 

<c:set var="url" value="http://www.google.co.kr/"/>

<c:import url="${url}" var="u"/>

<c:out value="${url}"/> 가져옵니다.

<hr>

<base href="<c:out value="${url}"/>">

    <c:out value="${u}" escapeXml="false"/>

</base>

<hr>

 

<c:set var="url" value="http://www.okjsp.pe.kr"/>

<c:import url="${url}" var="u"/>

<c:out value="${url}"/> 가져옵니다.

<hr>

<pre><c:out value="${u}"/></pre>

<hr>

 

<c:set var="url" value="ftp://ftp.dacom.co.kr"/>

<c:import url="${url}" var="u"/>

<c:out value="${url}"/> 가져옵니다.

<hr>

<pre><c:out value="${u}"/></pre>

<hr>

 

<c:set var="url" value="jstlcore02.jsp"/>

<c:import url="${url}" var="u">

    <c:param name="name" value="admin"/>

</c:import>

<c:out value="${url}"/> 가져옵니다.

<hr>

<c:out value="${u}" escapeXml="false"/>

<hr>

4개의 주소를 불러오는 예제이다.

처음에는 구글사이트를 불러서 그대로 표시한다. escapeXml 속성을 false 로 해야 브라우저에 태그가 나타나지 않는다.

<base href=""> 태그는 소스를 가져왔을 때 상대경로에 있는 주소의 기준점이 된다. 따라서 상대경로로 표시된 이미지 등을 깨지지 않고 표시할 수 있다.

두번째는 okjsp 사이트를 가져와서 소스를 보여준다. escapeXml 속성이 생략되면 true값으로 지정되고, 태그를 볼 수 있게 했다.

세번째는 ftp.dacom.co.kr 에 있는 내용을 가져온다.

마지막에는 앞에서 보았던 jstlcore02.jsp 를 불러오는 예제이다. <c:param/> 태그를 내부에 두어서 파라메터값을 보낼 수 있다.

 

4.8          <c:url/>

<c:url/> 태그는 컨텍스트를 자동으로 추가해서 주소를 자동으로 생성해준다. context 속성이 지정되었을 경우 value context 의 값은 / 로 시작을 해야된다. context 속성이 생략되면 당연히 현재의 컨텍스트가 적용된다. <c:url/> 의 형식은 다음과 같다.

Syntax 1: Body 없는 경우

<c:url value="value" [context="context"]

        [var="varName"] [scope="{page|request|session|application}"]/>

 

Syntax 2: Body 있는 경우 쿼리 스트링 파라메터 지정

<c:url value="value" [context="context"]

        [var="varName"] [scope="{page|request|session|application}"]>

    <c:param> 서브태그

</c:url>

 

다음은 간단한 예제이다.

예제 8.   jstlcore05.jsp

<% response.setContentType("text/html"); %>

<%@ taglib uri="http://java.sun.com/jstl/core" prefix="c"%>

 

<c:url value="/images/tomcat.gif"/>

<img src="<c:url value="/images/tomcat.gif"/>">

코드를 실행하면, <img src="/chap9/images/tomcat.gif">  와 같이 출력이 된다. ROOT 컨텍스트일 경우는 <img src="/images/tomcat.gif"> 와 같이 출력된다.

다른 컨텍스트를 사용하는 경우 정적인 컨텐츠의 주소를 쓰기 위해서는 jsp 에서는 <img src="<%=request.getContextPath()%>/images/tomcat.gif"> 와 같이 처리를 해주어야 되었다. 이런 경우를 대체하는 태그이다.

 

4.9          <c:redirect/>

response.sendRedirect() 를 대체하는 태그이다. 컨텍스트를 지정해서 다른 컨텍스트로 이동이 가능하다.

<c:redirect/> 의 형식은 다음과 같다.

Syntax 1: Body 없는 경우

<c:redirect url="value" [context="context"]/>

 

Syntax 2: Body 있는 경우 쿼리 스트링 파라메터 지정

<c:redirect url="value" [context="context"]/>

    <c:param> 서브태그

</c:redirect>

 

다음은 간단한 예제이다.

예제 9.   jstlcore06.jsp

<%@ taglib uri="http://java.sun.com/jstl/core" prefix="c"%>

 

<c:redirect url="/jstlcore01.jsp"/>

<c:url/> 태그와 마찬가지로 context 속성을 지정하면, value context 의 값은 / 로 시작을 해야된다. <c:param/> 태그를 중첩시켜서 사용할 수도 있다.

 

4.10       <c:param/>

<c:param/> 은 다음과 같이 url 에 바로 붙여서 쓸 수도 있다.

<c:import url="/exec/doIt">

  <c:param name="action" value="register"/>

</c:import>

이 방법은 아래 태그와 같은 효과가 있다.

<c:import url="/exec/doIt?action=register"/>

 

이제까지 기본적인 태그인 core 태그들에 대해서 살펴보았다. 다음 섹션에서 출력 형식을 지정하는 fmt 태그를 살펴보도록 하겠다.

 

5           JSTL 국제화 지역화 태그

다국어 문서를 처리할 때 유용하고, 날짜와 숫자 형식을 다루는 fmt 태그는 다음과 같은 종류가 있다.

기능

태그

prefix

Locale 설정

setLocale, requestEncoding

fmt

메시지 처리

bundle, message(param), setBundle

숫자 날짜 형식

formatNumber, formatDate, parseDate, parseNumber, setTimeZone, timeZone

 

fmt 태그를 사용하기 위해서 페이지 상단에 다음과 같이 선언되어야 된다.

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

 

 

5.1          <fmt:setLocale/>

<fmt:setLocale/> 의 형식은 다음과 같다.

Syntax

<fmt:setLocale value="locale"

        [variant="variant"]

        [scope="{page|request|session|application}"]/>

 

 

다국어 페이지를 만들 경우 사용할 경우 ResourceBundle 로 불러오는 *.properties 파일들과 연계되어서 사용할 수 있다. value 속성에 들어가는 locale 값은 [1]언어코드와 [2]국가코드로 이루어진다. 생략될 경우 톰캣 서버의 기본값으로 설정이 되고, 둘 중에 하나만 사용할 수도 있다. http://java.sun.com/j2se/1.4.1/docs/api/java/util/Locale.html api 에 보다 상세한 설명이 있다.

예제 10.                          jstlfmt01.jsp

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

<pre>

default locale : <%= response.getLocale() %>

set locale : ko <fmt:setLocale value="ko" />

now: <%= response.getLocale() %>

set locale : ja <fmt:setLocale value="ja" />

now: <%= response.getLocale() %>

set locale : en <fmt:setLocale value="en" />

now: <%= response.getLocale() %>

</pre>

예제를 값을 변경시켜서 실행하면, response 쪽에 영향을 주는 것을 알 수 있다.

 

5.2          <fmt:requestEncoding/>

다음으로 볼 것은 request.setCharacterEncoding() 역할을 하는 <fmt:requestEncoding/> 태그이다. 형식은 다음과 같다.

Syntax

<fmt:requestEncoding [value="charsetName"]/>

 

파라메터를 MS949 로 인코딩하는 경우 다음과 같이 사용하면 된다.

<fmt:requestEncoding value="MS949"/>

 

예제 11.                         jstlfmt02.jsp

<%@ page contentType="text/html;charset=euc-kr" %>

<%@ taglib uri="http://java.sun.com/jstl/core" prefix="c" %>

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

<fmt:requestEncoding value="euc-kr"/>

파라메터:<c:out value="${param.id}"/>

<form method="post">

    <input type="text" name="id">

    <input type="submit">

</form>

페이지 인코딩이 적용된 경우 request 에서 가져오는 parameter 와 맞지 않는 경우에 사용한다. 서버마다 차이가 있기 때문에, 테스트를 통해서 자신의 환경에 맞게 사용해야 된다. 톰캣4.1.19 의 경우 인코딩을 적용하지 않고도, 해결되는데 다음과 같은 형태로 사용할 수 있다.

예제 12.                         jstlfmt02b.jsp

<%@ taglib uri="http://java.sun.com/jstl/core" prefix="c"%>

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

<% response.setContentType("text/html;"); %>

파라메터:<c:out value="${param.id}"/>

<form method="post">

    <input type="text" name="id">

    <input type="submit">

</form>

 

 

5.3          <fmt:bundle/>

properties 확장자를 사용하는 자원 파일을 읽어오는 역할을 하는 <fmt:bundle/> 에 대해서 알아보자. 형식은 다음과 같다.

Syntax

<fmt:bundle basename="basename"

        [prefix="prefix"]>

    body content

</fmt:bundle>

 

basename 속성에 지정된 properties 파일을 찾아서 locale 에 따라 읽어들인다.

properties 파일은 보통 WEB-INF/classes 아래에 위치하며 디렉토리의 깊이에 따라서 패키지형식의 이름을 취한다. TestBundle.properties 파일이 com/itexpert/chap9/msg 디렉토리에 있다면 basename="com.itexpert.chap9.msg.TestBundle" 이라고 지정하면 된다.

locale ko 라면 TestBundle_ko.properties 파일을 읽어오게 되며, locale 이 맞지 않는 경우에는 TestBundle.properties 처럼 코드가 붙지 않은 파일을 읽어온다.

prefix 속성은 key 명칭이 공통적인 부분을 지정해서 body 에서 표현되는 key 를 단축시킨다. import 에서 패키지명을 지정하면 클래스명만 쓸 수 있는 것과 같이 생각할 수 있다.

properties 파일의 경우 j2sdk /bin/native2ascii.exe 를 이용해서 유니코드로 변환될 필요가 있으나, 파일 수가 많을 경우 ant <native2ascii> 태스크를 이용해서 쉽게 처리할 수 있다. chap9.zip 소스에 포함된 build.xml 파일에 보면 다음과 같은 태스크가 지정되어 있다.

<native2ascii encoding="EUC-KR"

            src="${src.home}"

            dest="${build.home}/WEB-INF/classes"

            includes="**/*_ko.properties"/>

 

5.4          <fmt:message/>

번들 태그에서 정한 값들을 가져오는 태그는 <fmt:message/>이다. 다음은 <fmt:message/> 태그의 형식이다.

Syntax 1: body 없는 경우

<fmt:message key="messageKey"

        [bundle="resourceBundle"]

        [var="varName"]

        [scope="{page|request|session|application}"]/>

 

Syntax 2: 메시지 파라메터를 지정하는 body가 있는 경우

<fmt:message key="messageKey"

        [bundle="resourceBundle"]

        [var="varName"]

        [scope="{page|request|session|application}"]>

    <fmt:param> 서브태그

</fmt:message>

 

Syntax 3: 키와 선택적 메시지 파라메터를 지정하는 body가 있는 경우

<fmt:message [bundle="resourceBundle"]

        [var="varName"]

        [scope="{page|request|session|application}"]>

    key

    선택적 <fmt:param> 서브태그

</fmt:message>

 

번들에 있는 key 값을 불러온다. bundle 속성으로 번들을 직접 설정할 수도 있고, <fmt:bundle/> 태그 사이에 중첩되어서 키값만 받아서 출력할 수 있다.

예제 13.                         TestBundle.properties

greeting=Hello.

admin=kenu

 

예제 14.                         TestBundle_ko.properties

greeting=안녕하세요.

admin=허광남

 

예제 15.                         jstlfmt03.jsp

<%@ taglib uri="http://java.sun.com/jstl/core" prefix="c"%>

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

<fmt:setLocale value="ko"/>

<fmt:bundle basename="com.itexpert.chap9.msg.TestBundle">

 <fmt:message>greeting</fmt:message><br>

 <fmt:message>admin</fmt:message>

</fmt:bundle>

 

locale "ko" 로 지정했기 때문에 TestBundle_ko.properties 파일을 읽어온다. "en"으로 정하거나 맞는 프로퍼티가 없을 경우는 기본프로퍼티인 TestBundle.properties 파일을 읽는다.

<fmt:message> 를 통해서 greeting 키와 admin 키를 읽어와서 표시한다.

 

5.5          <fmt:setBundle/>

페이지 전체에서 사용할 수 있는 번들을 지정할 수 있는데, 이에 대한 지정은 <fmt:setBundle/> 태그가 담당한다. var 속성에서 정한 변수를 이후에 나오는 <fmt:message/> 태그에서 basename 속성에 변수명으로 대체할 수 있다. <fmt:setBundle/> 의 형식은 다음과 같다.

Syntax

<fmt:setBundle basename="basename"

        [var="varName"]

        [scope="{page|request|session|application}"]/>

 

예제 15. jstlfmt03.jsp 는 다음과 같이 수정할 수 있다.

예제 16.                         jstlfmt04.jsp

<%@ taglib uri="http://java.sun.com/jstl/core" prefix="c"%>

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

<fmt:setLocale value="ko"/>

<fmt:setBundle var="testBundle"

    basename="com.itexpert.chap9.msg.TestBundle"/>

 

<fmt:message bundle="${testBundle}" key="greeting"/><br>

<fmt:message bundle="${testBundle}" key="admin"/><br>

var 에서 변수를 설정할 때는 EL 을 사용하지 않는다. 다른 태그에서 이것을 불러오는 경우는 EL 을 사용해서 불러온다. testBundle 변수의 사용을 눈여겨 볼만하다.

 

5.6          <fmt:formatNumber/>

다음은 숫자 형식을 표현하는 <fmt:formatNumber/> 태그이고 형식은 다음과 같다.

Syntax 1: body 없는 경우

<fmt:formatNumber value="numericValue"

        [type="{number|currency|percent}"]

        [pattern="customPattern"]

        [currencyCode="currencyCode"]

        [currencySymbol="currencySymbol"]

        [groupingUsed="{true|false}"]

        [maxIntegerDigits="maxIntegerDigits"]

        [minIntegerDigits="minIntegerDigits"]

        [maxFractionDigits="maxFractionDigits"]

        [minFractionDigits="minFractionDigits"]

        [var="varName"]

        [scope="{page|request|session|application}"]/>

 

Syntax 2: 형식에 맞출 수치가 body에 있는 경우

<fmt:formatNumber [type="{number|currency|percent}"]

        [pattern="customPattern"]

        [currencyCode="currencyCode"]

        [currencySymbol="currencySymbol"]

        [groupingUsed="{true|false}"]

        [maxIntegerDigits="maxIntegerDigits"]

        [minIntegerDigits="minIntegerDigits"]

        [maxFractionDigits="maxFractionDigits"]

        [minFractionDigits="minFractionDigits"]

        [var="varName"]

        [scope="{page|request|session|application}"]>

    형식화될 수치

</fmt:formatNumber>

 

 

각 속성을 정리한 표는 다음과 같다.

속성

동적값

Type

설명

value

true

String 또는

Number

형식화될 수치

type

true

String

숫자, 통화, 퍼센트 중 어느 것으로 표시할 지 지정 {number|currency|percent}

pattern

true

String

사용자가 지정한 형식 패턴.

currencyCode

true

String

ISO 4217 통화 코드. 통화 형식일 때만 적용(type="currency")

currencySymbol

true

String

통화 기호. 통화 형식일 때만 적용

(type="currency")

groupingUsed

true

boolean

형식 출력에 그룹 분리기호를 포함할지 여부

maxIntegerDigits

true

int

형식 출력에서 integer 최대 자리수

minIntegerDigits

true

int

형식 출력에서 integer 최소 자리수

maxFractionDigits

true

int

형식 출력에서 소수점 이하 최대 자리수.

minFractionDigits

true

int

형식 출력에서 소수점 이하 최소 자리수.

var

false

String

형식 출력 결과 문자열을 담는 scope에 해당하는 변수명

scope

false

String

var scope

 

5.7          <fmt:parseNumber/>

반대로 정해진 패턴을 문자열에서 수치를 파싱해내는 태그는 <fmt:parseNumber/>이며 형식은 다음과 같다.

Syntax 1: body가 없는 경우

<fmt:parseNumber value="numericValue"

        [type="{number|currency|percent}"]

        [pattern="customPattern"]

        [parseLocale="parseLocale"]

        [integerOnly="{true|false}"]

        [var="varName"]

        [scope="{page|request|session|application}"]/>

 

Syntax 2: 파싱할 수치를 body 에 갖고 있는 경우

<fmt:parseNumber [type="{number|currency|percent}"]

        [pattern="customPattern"]

        [parseLocale="parseLocale"]

        [integerOnly="{true|false}"]

        [var="varName"]

        [scope="{page|request|session|application}"]>

    파싱할 수치

</fmt:parseNumber>

 

 

각 속성을 정리한 도표는 다음과 같다.

속성

동적값

Type

설명

value

true

String 또는

Number

파싱할 수치

type

true

String

숫자, 통화, 퍼센트 중 어느 것으로 표시할 지 지정 {number|currency|percent}

pattern

true

String

사용자가 지정한 형식 패턴.

parseLocale

true

String 또는

java.util.Locale

파싱 작업의 기본 형식 패턴(숫자, 통화, 퍼센트 각각)을 제공하는 Locale

integerOnly

true

boolean

주어진 값에서 integer 부분만 파싱할지 여부를 지정

var

false

String

파싱 결과 (java.lang.Number 타입)를 담는 scope에 해당하는 변수명

scope

false

String

var scope

 

5.8          <fmt:formatDate/>

다음은 날짜 형식을 표현하는 <fmt:formatDate/> 태그이고 형식은 다음과 같다.

Syntax

<fmt:formatDate value="date"

        [type="{time|date|both}"]

        [dateStyle="{default|short|medium|long|full}"]

        [timeStyle="{default|short|medium|long|full}"]

        [pattern="customPattern"]

        [timeZone="timeZone"]

        [var="varName"]

        [scope="{page|request|session|application}"]/>

 

 

각 속성을 정리한 도표는 다음과 같다.

속성

동적값

Type

설명

value

true

java.util.Date

형식화될 Date time

type

true

String

형식화할 데이터가 시간, 날짜, 모두 인지 셋 중 하나를 지정한다.

dateStyle

true

String

미리 정의된 날짜 형식. Java.text.DateFormat 클래스에 정의된 문법을 따른다. type="date", type="body", type속성이 생략된 경우 사용.

timeStyle

true

String

미리 정의된 날짜 형식. Java.text.DateFormat 클래스에 정의된 문법을 따른다.

type="time", type="body" 의 경우 사용.

pattern

true

String

사용자 지정 형식 스타일

timeZone

true

String 또는

java.util.TimeZone

형식화 시간에 나타날 타임존

var

false

String

형식 출력 결과 문자열을 담는 scope에 해당하는 변수명

scope

false

String

var scope

 

5.9          <fmt:parseDate/>

정해진 패턴의 문자열에서 날짜를 파싱해내는 태그는 <fmt:parseDate/>이며 형식은 다음과 같다.

Syntax 1: body 없는 경우

<fmt:parseDate value="dateString"

        [type="{time|date|both}"]

        [dateStyle="{default|short|medium|long|full}"]

        [timeStyle="{default|short|medium|long|full}"]

        [pattern="customPattern"]

        [timeZone="timeZone"]

        [parseLocale="parseLocale"]

        [var="varName"]

        [scope="{page|request|session|application}"]/>

 

Syntax 2: 파싱한 값이 body 에 있는 경우

<fmt:parseDate [type="{time|date|both}"]

        [dateStyle="{default|short|medium|long|full}"]

        [timeStyle="{default|short|medium|long|full}"]

        [pattern="customPattern"]

        [timeZone="timeZone"]

        [parseLocale="parseLocale"]

        [var="varName"]

        [scope="{page|request|session|application}"]>

    파싱할 Date time

</fmt:parseDate>

 

 

각 속성을 정리한 도표는 다음과 같다.

속성

동적값

Type

설명

value

true

java.util.Date

파싱할 Date time

type

true

String

파싱할 데이터가 시간, 날짜, 모두 인지 셋 중 하나를 지정한다.

dateStyle

true

String

미리 정의된 날짜 형식. Java.text.DateFormat 클래스에 정의된 문법을 따른다. type="date", type="body", type속성이 생략된 경우 사용.

timeStyle

true

String

미리 정의된 날짜 형식. Java.text.DateFormat 클래스에 정의된 문법을 따른다.

type="time", type="body" 의 경우 사용.

pattern

true

String

사용자 지정 형식 스타일

timeZone

true

String 또는

java.util.TimeZone

형식화 시간에 나타날 타임존

parseLocale

true

String 또는

java.util.Locale

파싱하는 동안 적용될 미리 정의된 형식 스타일의 Locale

var

false

String

파싱 결과(java.util.Date)를 담는 scope에 해당하는 변수명

scope

false

String

var scope

 

다음은 숫자, 날짜에 대한 태그 사용 예제이다.

예제 17.                         jstlfmt05.jsp

<%@ page pageEncoding="MS949" %>

<%@ taglib uri="http://java.sun.com/jstl/core" prefix="c" %>

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

<pre><fmt:setLocale value="ko_KR"/>

number  : <fmt:formatNumber value="9876543.61" type="number"/>

currency: <fmt:formatNumber value="9876543.61" type="currency"/>

percent : <fmt:formatNumber type="percent">9876543.61</fmt:formatNumber>

 

pattern=".000"    :<fmt:formatNumber value="9876543.61" pattern=".000" />

pattern="#,#00.0#":<fmt:formatNumber value="9876543.612345" pattern="#,#00.0#"/>

 

<jsp:useBean id="now" class="java.util.Date"/>

<c:out value="${now}"/>

date: <fmt:formatDate value="${now}" type="date"/>

time: <fmt:formatDate value="${now}" type="time"/>

both: <fmt:formatDate value="${now}" type="both"/>

 

default:<fmt:formatDate value="${now}"

            type="both" dateStyle="default" timeStyle="default"/>

short  :<fmt:formatDate value="${now}"

            type="both" dateStyle="short"   timeStyle="short"  />

medium :<fmt:formatDate value="${now}"

            type="both" dateStyle="medium"  timeStyle="medium" />

long   :<fmt:formatDate value="${now}"

            type="both" dateStyle="long"    timeStyle="long"   />

full   :<fmt:formatDate value="${now}"

            type="both" dateStyle="full"    timeStyle="full"   />

 

pattern="yyyyMMdd HHmmss"

         <fmt:formatDate value="${now}" type="both"

            pattern="yyyyMMdd HHmmss"/>

</pre>

 

 

5.10       <fmt:setTimeZone/>, <fmt:timeZone/>

특정 스코프의 타임존을 설정하는 <fmt:setTimeZone/> 태그의 형식은 다음과 같다.

Syntax

<fmt:setTimeZone value="timeZone"

        [var="varName"]

        [scope="{page|request|session|application}"]/>

 

타임존을 부분 적용하는 <fmt:timeZone/> 태그는 다음과 같은 형식이다.

Syntax

<fmt:timeZone value="timeZone">

    body content

</fmt:timeZone>

 

타임존을 적용한 시간 표시 예제이다.

예제 18.                         jstlfmt06.jsp

<%@ taglib uri="http://java.sun.com/jstl/core" prefix="c"%>

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

<pre><fmt:setLocale value="ko_KR"/>

<jsp:useBean id="now" class="java.util.Date"/>

 

default: <c:out value="${now}"/>

Korea   KST  : <fmt:formatDate value="${now}" type="both" dateStyle="full"

                   timeStyle="full"/>

<fmt:timeZone value="GMT">

Swiss   GMT  : <fmt:formatDate value="${now}" type="both" dateStyle="full"

                   timeStyle="full"/>

</fmt:timeZone>

<fmt:timeZone value="GMT-8">

NewYork GMT-8: <fmt:formatDate value="${now}" type="both" dateStyle="full"

                   timeStyle="full"/>

</fmt:timeZone>

</pre>

 

 

이상으로 태그를 이용해서 숫자, 날짜, 시간 등을 표현하는 방법을 알아보았다. 태그의 속성들이 직관적이기 때문에 사용에 그리 불편하지 않을 것이다.

 

 

6           JSTL SQL 태그

DataSource 를 이용해서 SQL을 처리하는 sql 태그는 다음과 같은 것들이 있다.

기능

태그

prefix

DataSource 설정

SetDataSource

sql

SQL

query (dateParam, param) , update (dateParam, param) ,

transaction

 

sql 태그를 사용하기 위해서 페이지 상단에 다음과 같이 선언되어야 된다.

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

 

6.1          <sql:setDataSource/>

DataSource 를 지정하는 방식은 <sql:setDataSource/> 태그의 사용법은 다음과 같다.

Syntax

<sql:setDataSource

        {dataSource="dataSource" |

            url="jdbcUrl"

            [driver="driverClassName"]

            [user="userName"]

            [password="password"]}

        [var="varName"]

        [scope="{page|request|session|application}"]/>

 

오라클에서 사용을 한다면 다음과 같이 DataSource 를 설정할 수 있다.

<sql:setDataSource

            url="jdbc:oracle:thin:@localhost:1521:ora81"

            driver="oracle.jdbc.driver.OracleDriver"

            user="scott"

            password="tiger"

        var="okjspDS"

        scope="application" />

 

이미 컨텍스트에 JNDI 설정이 되어있다면 다음과 같이 바로 불러서 사용하거나 <sql:query/> 에서 바로 사용할 수 있다.

기존의 dataSource 를 불러와 사용하는 경우

<sql:setDataSource

        dataSource="jdbc/myora81"

        var="okjspDS"

        scope="application" />

 

<sql:query/> 에서 바로 사용하는 경우

<sql:query var="emp"

        dataSource="jdbc/myora81">

 

6.2          <sql:query/>

java 와는 달리 sql 문장을 문자열로 연결하지 않아도 가독성을 높여서 작성할 수 있다. <sql:query/>태그의 형식은 다음과 같다.

 

Syntax 1: body 없는 경우

<sql:query sql="sqlQuery"

        var="varName" [scope="{page|request|session|application}"]

        [dataSource="dataSource"]

        [maxRows="maxRows"]

        [startRow="startRow"]/>

 

Syntax 2: body 에 쿼리의 파라메터가 있는 경우

<sql:query sql="sqlQuery"

        var="varName" [scope="{page|request|session|application}"]

        [dataSource="dataSource"]

        [maxRows="maxRows"]

        [startRow="startRow"]>

    <sql:param> 액션들

</sql:query>

 

Syntax 3: 쿼리와 파라메터들이 body 에 있는 경우

<sql:query var="varName"

        [scope="{page|request|session|application}"]

        [dataSource="dataSource"]

        [maxRows="maxRows"]

        [startRow="startRow"]>

    sqlQuery

    선택적 <sql:param> 액션들

</sql:query>

 

 

6.3          <sql:dateParam/> , <sql:param/>

파라메터에는 두 가지가 있는데, 날짜 형식의 <sql:dateParam/> 와 일반적인 <sql:param/>태그가 있으며 형식은 다음과 같다.

Syntax

<sql:dateParam value="value" type="[timestamp|time|date]"/>

 

Syntax 1: value 속성에 파라메터 값이 지정된 경우

<sql:param value="value"/>

 

Syntax 2: body 내용에 파라메터 값이 지정된 경우

<sql:param>

    parameter value

</sql:param>

<sql:dateParam/> java.sql.PreparedStatement.setTimestamp() 역할을 하고,

<sql:param/> java.sql.PreparedStatement.setString() 의 역할을 한다. 바인드변수의 순서에 따라서 써주면 된다.

 

7장의 jdbc_resultset.jsp 파일을 JSTL로 바꾸어서 변경한 것이다.

예제 19.                         jstlsql01.jsp

<%@ page pageEncoding="MS949" %>

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

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

<%@ taglib prefix="c" uri="http://java.sun.com/jstl/core" %>

<fmt:setLocale value="ko" />

<sql:query var="emp"

        dataSource="jdbc/myora81">

SELECT  EMPNO AS 사원번호, ENAME AS 이름,

            SAL AS 월급여, HIREDATE AS 입사일

    FROM EMP

</sql:query>

 

<table border="1">

  <tr>

<%-- 필드의 정보를 출력한다.            --%>

  <c:forEach var="columnName" items="${emp.columnNames}">

    <th><c:out value="${columnName}"/></th>

  </c:forEach>

 

<%-- 데이터를 한 줄씩 출력한다.         --%>

  <c:forEach var="row" items="${emp.rowsByIndex}">

    <tr>

<%-- 필드의 길이만큼 반복한다.          --%>

      <c:forEach var="column" items="${row}" varStatus="i">

        <c:choose>

          <c:when test="${i.index==3}">

      <td><fmt:formatDate value="${column}" pattern="yyyy/MM/dd"/></td>

          </c:when>

          <c:otherwise>

      <td><c:out value="${column}"/></td>

          </c:otherwise>

        </c:choose>

      </c:forEach>

  </c:forEach>

</table>

<hr>

<table border="1">

  <c:forEach var="row" items="${emp.rows}">

  <tr>

    <td>번호: <c:out value="${row['사원번호']}"/></td>

    <td>이름: <c:out value="${row['이름']}"/></td>

  </tr>

  </c:forEach>

</table>

 

dataSource="jdbc/myora81" JNDI 7장에서 설명한 것처럼 컨텍스트에 설정된 DataSource 명이다.

SQL문은 보기 좋게 정렬을 해도 문자열로 덧붙일 필요가 없다. body 에 있는 sql문을 실행한 결과는 emp 라는 변수에 담겨서 이후에 사용이 된다. 이 변수는 ResultSet 과 같은데, JSTL에서 확장한 ResultSet 이고, javax.servlet.jsp.jstl.sql public interface Result 클래스로 내부적으로 정의된다. 지원하는 메소드는 다음과 같다.

javax.servlet.jsp.jstl.sql

public interface Result

public java.util.SortedMap[] getRows()

public Object[][] getRowsByIndex()

public String[] getColumnNames()

public int getRowCount()

public boolean isLimitedByMaxRows()

 

 

위와 같은 메소드들이 내부적으로 정의되어있기 때문에 각각의 getter 메소드들을 사용해서 변수 emp를 활용할 수 있다.

<c:forEach/> items 에 있는 ${emp.columnNames} getColumnNames() 메소드를 불렀다는 것을 알 수 있다. 이전의 7장에서 ResultSetMetaData 를 활용해서 뽑아낸 정보와 같은 효과를 볼 수 있다.

테이블 내용을 반환하는 ${emp.rowsByIndex} 도 유념할 만하다. 한 행을 row라는 변수에 넣은 뒤에 다음의 <c:forEach/> 에서 이 row변수의 컬럼별로 내용을 출력한다.

column 이라는 변수에 넣은 뒤에 column index 3일 경우 날짜형식을 출력하기 위해서 <fmt:formatDate/> 태그를 사용했고, 그 외의 경우는 바로 출력하게 했다.

다음 <c:forEach/> 에서는 결과를 SortedMap 배열에 넣은 뒤에 한 줄씩 빼서 컬럼이름으로 빼내는 방식이다.

 

6.4          <sql:update/>

java.sql.Statement.executeUpdate() 메소드에 해당하는 <sql:update/> 태그의 형식은 다음과 같다.

Syntax 1: body 없는 경우

<sql:update sql="sqlUpdate"

        [dataSource="dataSource"]

        [var="varName"] [scope="{page|request|session|application}"]/>

 

Syntax 2: update 파라메터가 body에 있는 경우

<sql:update sql="sqlUpdate"

        [dataSource="dataSource"]

        [var="varName"] [scope="{page|request|session|application}"]>

    <sql:param> 액션들

</sql:update>

 

Syntax 3: update 문과 선택적 update 파라메터가 body에 있는 경우

<sql:update [dataSource="dataSource"]

        [var="varName"] [scope="{page|request|session|application}"]>

    sqlUpdate

    선택적 <sql:param> 액션들

</sql:update>

형식과 동작은 <sql:query/> 태그와 동일하다. 다른 점은 executeUpdate() 메소드를 수행하기 때문에 DB에 변경을 가할 수 있다는 것이다.

 

6.5          <sql:transaction/>

트랜잭션을 구현하는 <sql:transaction/> 태그의 형식은 다음과 같다.

Syntax

<sql:transaction [dataSource="dataSource"]

        [isolation=isolationLevel]>

    <sql:query> <sql:update> 문들

</sql:transaction>

 

isolationLevel ::= "read_committed"

                | "read_uncommitted"

                | "repeatable_read"

                | "serializable"

격리 수준(isolationLevel) java.sql.Connection setTransactionIsolation() 메소드를 사용한다. 정리해 놓은 도표는 7 JDBC Transaction 을 참고하기 바란다.

 

7           JSTL XML 태그

7.1          xml 태그와 XPath

xml 태그를 사용하기 위해서는 XPath 를 먼저 이해할 필요가 있다. xml 소스 트리의 정확한 위치를 지정해주기 위한 경로지정 문법이며 XSLT XPointer 를 위해서 만들어진 것이다. xml 엘리먼트들을 노드(node) 로 접근한다. 파일 시스템과 유사하며 다음과 같은 특성이 있다.

l        / 로 시작하면 절대경로처럼 root node 에서 시작된다.

l        //로 시작할 경우는 모든 영역에서 해당 엘리먼트를 선택하게 된다.

l        표시는 이전 엘리먼트 아래의 모든 자식 엘리먼트를 나타낸다.

l        동일한 엘리먼트들이 있을 경우, [] 안에 포함된 숫자는 엘리먼트의 순번이다. 조건식이 올 경우 해당하는 것이 선택된다. last() 일 경우는 맨 마지막 엘리먼트를 표시한다.

l        속성은 @ 로 시작된다.

l        normalize-space() 함수는 앞뒤 공백을 제거하는 trim() 역할을 한다.

이 장에 나오는 XPath의 기능은 이 정도로 소개하겠고, XPath에 관한 보다 자세한 내용은 이 장의 마지막에 소개한 인터넷 튜토리얼을 참고하기 바란다.

 

JSTL에서 XPath를 통해서 내장객체에 쉽게 접근할 수 있다.

표현

매핑

$foo

pageContext.findAttribute("foo")

$param:foo

request.getParameter("foo")

$header:foo

request.getHeader("foo")

$cookie:foo

maps to the cookie's value for name foo

$initParam:foo

application.getInitParameter("foo")

$pageScope:foo

pageContext.getAttribute(

"foo", PageContext.PAGE_SCOPE)

$requestScope:foo

pageContext.getAttribute(

"foo", PageContext.REQUEST_SCOPE)

$sessionScope:foo

pageContext.getAttribute(

"foo", PageContext.SESSION_SCOPE)

$applicationScope:foo

pageContext.getAttribute(

"foo", PageContext.APPLICATION_SCOPE)

예를 들어서 다음 문장은 parameter 로 받은 "name"의 값이 bar엘리먼트의 x속성의 값과 같은 것들을 선택하게 된다.

/foo/bar[@x=$param:name]

 

xml 태그는 다음과 같은 것들이 있다.

기능

태그

prefix

기본

out, parse, set

x

흐름 제어

choose (when, otherwise), forEach, if

변환

transform (param)

 

xml 태그를 사용하기 위해서 페이지 상단에 다음과 같이 선언되어야 된다.

<%@ taglib uri="http://java.sun.com/jstl/xml" prefix="x"%>

 

7.2          <x:out/>

XPath에 지정한 패턴에 따라 xml내용을 출력하는 <x:out/> 태그의 형식은 다음과 같다.

Syntax

<x:out select="XPathExpression" [escapeXml="{true|false}"]/>

 

 

7.3          <x:parse/>

xml문서를 읽어서 파싱하는 <x:parse/> 태그는 다음과 같은 형식이다.

Syntax 1: String 또는 Reader 객체로 지정된 XML 문서

<x:parse xml="XMLDocument"

        {var="var" [scope="scopeName"]|varDom="var" [scopeDom="scopeName"]}

        [systemId="systemId"]

        [filter="filter"]/>

 

Syntax 2: body 내용으로 지정된 XML 문서

<x:parse

        {var="var" [scope="scopeName"]|varDom="var" [scopeDom="scopeName"]}

        [systemId="systemId"]

        [filter="filter"]>

    파싱할 XML 문서

</x:parse>

scopeName {page|request|session|application} 중의 하나

 

 

7.4          <x:set/>

XPath에 따라 선택된 내용을 변수에 저장하는 <x:set/> 태그의 형식은 다음과 같다.

Syntax

<x:set select="XPathExpression"

        var="varName" [scope="{page|request|session|application}"]/>

 

7.5          <x:if/>

<c:if/> 태그와 마찬가지로 xml태그에도 <x:if/> 가 있고 형식은 <c:if/> 태그와 유사하다. <x:if/>의 형식은 다음과 같다.

Syntax 1: Body 없는 경우

<x:if select="XPathExpression"

        var="varName" [scope="{page|request|session|application}"]/>

 

Syntax 2: Body 있는 경우

<x:if select="XPathExpression"

        [var="varName"] [scope="{page|request|session|application}"]>

    body content

</x:if>

test 속성 대신에 select 속성으로 진위를 따지는데, 다음 3가지 기준을 유념할 필요가 있다. 이 세 가지 기준은 <x:choose/> <x:when/> <x:forEach/> 에서도 동일하게 사용된다.

1. number true 인 때는 + 또는 – 0 도 아니고, NaN(Not A Number) 도 아닐 경우

2. node-set true 인 때는 empty 가 아닐 경우

3. string true 인 때는 길이가 0 이 아닐 경우

 

7.6          <x:choose/>,  <x:when/>,  <x:otherwise/>

<c:choose/> 태그와 마찬가지로 xml태그에도 <x:choose/> 가 있고 형식은 <c:choose/> 태그와 유사하다.

Syntax

<x:choose>

    body content (<x:when> and <x:otherwise> 서브태그)

</x:choose>

 

Syntax

<x:when select="XPathExpression">

    body content

</x:when>

 

Syntax

<x:otherwise>

    conditional block

</x:otherwise>

 

7.7          <x:forEach/>

<x:forEach/> 태그는 XPath에 따라서 해당하는 엘리먼트 수만큼 반복하게 된다.

Syntax

<x:forEach [var="varName"] select="XPathExpression">

    body content

</x:forEach>

 

 

xml 태그를 활용한 예제이다.

예제 20.                         jstlxml01.jsp

<%@ taglib uri="http://java.sun.com/jstl/core" prefix="c" %>

<%@ taglib uri="http://java.sun.com/jstl/xml" prefix="x" %>

<% response.setContentType("text/html;"); %>

<%-- 파라메터 받아서 출력 --%>

<c:if test="${!empty param.name}">

param: <x:out select="$param:name"/>

</c:if>

<form>

name: <input type="text" name="name">

<input type="submit">

</form>

<hr>

<%-- xml 데이터를 xdata 변수에 할당 --%>

<x:parse var="xdata">

<namecard>

    <person>

        <name>허광남</name>

        <id>남자</id>

        <email>kenu@email.com</email>

        <phone>111-2222-3333</phone>

    </person>

    <person>

        <name>노재춘</name>

        <id>남자</id>

        <email>suribada@email.com</email>

        <phone>222-3333-4444</phone>

    </person>

    <person>

        <name>이선재</name>

        <id>남자</id>

        <email>hsboy@email.com</email>

        <phone>333-4444-5555</phone>

    </person>

</namecard>

</x:parse>

<%-- XPath 를 이용해서 xdata에서 추출 --%>

<x:out select="$xdata//person[1]/name"/>

<x:out select="$xdata//person[last()]/name"/>

<hr>

<%-- person 으로 반복해서 email phone 출력 --%>

<table border="1">

<x:forEach select="$xdata//person">

<tr><td><x:out select="email" /></td>

<td><x:out select="phone" /></td></tr>

</x:forEach>

</table>

 

파라메터 name 의 접근은 EL에서는 ${param.name} 으로 사용하지만 XPath 에서는 $param:name 을 사용한다는 차이가 있다.

파라메터를 받아서 <x:out/> 으로 출력하는 부분이 제일 상단이고, 그 다음은 xml 데이터를 파싱하는 부분이다.

DTD 까지 쓰지 않아도 형식이 잘 갖춰지기만 하면 (well-formed) xml 데이터로 인식을 한다. 이것을 xdata라는 변수에 할당한 다음에 이후에 처리하게 된다.

 

xml 데이터는 파일로 따로 만든 후에 접근할 수 있다. 이때는 <c:import> 를 같이 사용하는데, 다음과 같이 쓸 수 있다.

예제 21.                         namecard.xml

<?xml version="1.0" encoding="euc-kr" ?>

<namecard>

    <person>

        <name>허광남</name>

        <id>남자</id>

        <email>kenu@email.com</email>

        <phone>111-2222-3333</phone>

    </person>

    <person>

        <name>노재춘</name>

        <id>남자</id>

        <email>suribada@email.com</email>

        <phone>222-3333-4444</phone>

    </person>

    <person>

        <name>이선재</name>

        <id>남자</id>

        <email>hsboy@email.com</email>

        <phone>333-4444-5555</phone>

    </person>

</namecard>

 

 

예제 22.                         jstlxml02.jsp

<%@ taglib uri="http://java.sun.com/jstl/core" prefix="c"%>

<%@ taglib uri="http://java.sun.com/jstl/xml" prefix="x"%>

<% response.setContentType("text/html;"); %>

<%-- namecard.xml 파일을 불러와 xdata 변수에 할당 --%>

<c:import url="namecard.xml" var="xmldata" />

<x:parse xml="${xmldata}" var="xdata"/>

 

<%-- XPath 를 이용해서 xdata에서 추출 --%>

<x:out select="$xdata//person[1]/name"/>

이하 생략

 

xdata 변수에 들어간 xml 에서 추출하는 방식은 XPath 를 사용한다고 했다.

$select="$xdata//person[1]/name" 에서 person[1] person 으로 사용하는 것과 같다. [] 안에는 순서가 들어가고 생략될 경우 첫 엘리먼트를 찾기 때문이다.

<x:forEache/> 태그로 <person> 엘리먼트 수만큼 반복하게 했다. 이때 자동으로 기준은 <person> 이 되기 때문에 그 이후에 <email> 이나 <phone> 엘리먼트들은 /person/email /person/phone 을 바로 참조하게 된다.

 

7.8          <x:transform/>, <x:param/>

xml xslt 파일을 결합해서 새로운 형식의 문서를 생성해 내는 <x:transform/>의 형식은 다음과 같다.

Syntax 1: Body 없는 경우

<x:transform

        xml="XMLDocument" xslt="XSLTStylesheet"

        [xmlSystemId="XMLSystemId"] [xsltSystemId="XSLTSystemId"]

        [{var="varName" [scope="scopeName"]|result="resultObject"}]>

 

Syntax 2: 변환 파라메터를 body에서 지정하는 경우

<x:transform

        xml="XMLDocument" xslt="XSLTStylesheet"

        [xmlSystemId="XMLSystemId"] [xsltSystemId="XSLTSystemId"]

        [{var="varName" [scope="scopeName"]|result="resultObject"}]>

    <x:param> 액션들

</x:transform>

 

Syntax 3: XML문서와 선택적 변환 파라메터들이 body에 지정된 경우

<x:transform

        xslt="XSLTStylesheet"

        xmlSystemId="XMLSystemId" xsltSystemId="XSLTSystemId"

        [{var="varName" [scope="scopeName"]|result="resultObject"}]>

    XML Document

    optional <x:param> actions

</x:parse>

scopeName {page|request|session|application} 중에 하나

 

var 속성에 지정된 결과와 result 속성에 지정된 결과의 차이점은 var 속성은 scope 지정해서 다른 곳에서도 사용할 수 있고, result 는 현재 페이지에서만 사용할 수 있다는 것이다.

또한 타입도 차이가 나는데, varorg.w3c.dom.Document , resultjavax.xml.transform.Result 객체로 저장이 된다.

 

xml의 파라메터를 지정하는 <x:param/> 태그의 형식은 다음과 같다.

Syntax

Syntax 1: value 속성에 파라메터 값이 지정된 경우

<x:param name="name" value="value"/>

 

Syntax 2: body 내용에 파라메터 값이 지정된 경우

<x:param name="name">

    parameter value

</x:param>

 

 

여기서 잠깐

<x:transform/> 태그를 사용할 때 jdk1.4 내에 있는 xalan jstl이 충돌을 일으킨다.

이런 경우, 톰캣 실행을 중지하고, jstl WEB-INF/lib디렉토리에 있는 xalan.jar 파일과 xercesImpl.jar 파일 두 개를 <CATALINA_HOME>/common/endorsed 디렉토리에 복사한다. 이전 버전의 xercesImpl.jar 파일을 덮어씌운다. 만일 이 과정이 생략되면, 다음과 같은 예외를 만나게 된다.

org.apache.xml.utils.WrappedRuntimeException: 
The output format must have a '{http://xml.apache.org/xslt}content-handler' property!

<x:transform/> 활용 예제를 보자.

예제 23.                         jstlxml03.jsp

<%@ page pageEncoding="MS949" %>

<%@ taglib prefix="c" uri="http://java.sun.com/jstl/core" %>

<%@ taglib prefix="x" uri="http://java.sun.com/jstl/xml" %>

 

<html>

<head>

  <title>JSTL: XML Support -- Transform</title>

</head>

<body bgcolor="#FFFFFF">

<c:set var="xml">

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

    <namecard>

        <person>

            <name>허광남</name>

            <id>남자</id>

            <email>kenu@email.com</email>

            <phone>111-2222-3333</phone>

        </person>

        <person>

            <name>노재춘</name>

            <id>남자</id>

            <email>suribada@email.com</email>

            <phone>222-3333-4444</phone>

        </person>

        <person>

            <name>이선재</name>

            <id>남자</id>

            <email>hsboy@email.com</email>

            <phone>333-4444-5555</phone>

        </person>

    </namecard>

</c:set>

 

<c:set var="xsl">

    <?xml version="1.0"?>

    <xsl:stylesheet

    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">

        <xsl:template match="/">

        <table border="1">

            <tr>

                <th>이름  </th>

                <th>이메일</th>

                <th>연락처</th>

            </tr>

        <xsl:for-each select="namecard/person">

            <tr>

                <td><xsl:value-of select="name" /></td>

                <td><xsl:value-of select="email" /></td>

                <td><xsl:value-of select="phone" /></td>

            </tr>

        </xsl:for-each>

        </table>

        </xsl:template>

 

    </xsl:stylesheet>

</c:set>

 

<x:transform xml="${xml}" xslt="${xsl}"/>

 

</body>

</html>

 

 

jsp 소스 안에 있는 xml(예제 21. namecard.xml) xsl을 따로 파일로 빼놓으면 아래와 같이 바뀐다.

예제 24.                         namecard.xsl

<?xml version="1.0" encoding="euc-kr" ?>

<xsl:stylesheet

xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">

    <xsl:template match="/">

    <table border="1">

        <tr>

            <th>이름  </th>

            <th>이메일</th>

            <th>연락처</th>

        </tr>

    <xsl:for-each select="namecard/person">

        <tr>

            <td><xsl:value-of select="name" /></td>

            <td><xsl:value-of select="email" /></td>

            <td><xsl:value-of select="phone" /></td>

        </tr>

    </xsl:for-each>

    </table>

    </xsl:template>

 

</xsl:stylesheet>

 

xsl 에 관한 문법적인 내용은 여기에서 다루지 않겠다.

namecard.xsl 파일은 namecard.xml html 을 입히는 역할을 하게 되며, 데이터를 제외한 html 틀을 갖고 있다고 볼 수 있다.

이 두 개의 파일을 하나로 합쳐서 html 코드를 만들어 내는 소스는 다음과 같다.

예제 25.                         jstlxml04.jsp

<%@ page pageEncoding="MS949" %>

<%@ taglib prefix="c" uri="http://java.sun.com/jstl/core" %>

<%@ taglib prefix="x" uri="http://java.sun.com/jstl/xml" %>

 

<html>

<head>

  <title>JSTL: XML Support -- Transform</title>

</head>

<body bgcolor="#FFFFFF">

<h1>연락처</h1>

<c:import var="xml" url="namecard.xml" charEncoding="MS949"/>

<c:import var="xsl" url="namecard.xsl" charEncoding="MS949"/>

 

<x:transform xml="${xml}" xslt="${xsl}"/>

 

</body>

</html>

 

jstlxml03.jsp 에서 <x:set/> 부분은 <c:import/> 로 바뀌었고, 파일을 불러올 때 charEncoding 속성을 통해서 인코딩해 주었다.

xml 변수와 xsl 변수 두 개를 파싱하지 않고 바로 <x:transform/> 을 통해서, jsp 파일에 출력했다.

<x:transform/> var 속성을 주면 출력되지 않고, 변수에 org.w3c.dom.Document 타입으로 저장된다.

 

 

이렇게 JSTL 4가지 표준 태그에 대해서 알아보았다. 프로그래밍의 기본인 조건, 반복, 연산이 가능하기 때문에 스크립틀릿을 거의 모두 제거할 수 있음을 알 수 있었다.

 

8           참고자료

JSTL 스펙

http://java.sun.com/products/jsp/jstl/

자카르타 taglibs

http://jakarta.apache.org/taglibs/doc/standard-doc/intro.html

Hans Bergsten article

JSTL 1.0: Standardizing JSP, Part 1

http://www.onjava.com/pub/a/onjava/2002/08/14/jstl1.html

JSTL 1.0: What JSP Applications Need, Part 2

http://www.onjava.com/pub/a/onjava/2002/09/11/jstl2.html

JSTL 1.0: What JSP Applications Need, Part 3

http://www.onjava.com/pub/a/onjava/2002/10/30/jstl3.html

JSTL in Action by Alex Garrett

http://www.codercoop.com/Members/alex_garrett/jstlnewapproach

XPath Tutorial

http://www.zvon.org/xxl/XPathTutorial/General/examples.html

XSL Tutorial

http://www.w3schools.com/xsl/

XSLT Tutorial

http://www.zvon.org/xxl/XSLTutorial/Books/Book1/



[1] http://ftp.ics.uci.edu/pub/ietf/http/related/iso639.txt

[2] http://userpage.chemie.fu-berlin.de/diverse/doc/ISO_3166.html