아래 내용을 정리 (2002년. JSP1.2 기준으로 작성된 글)
이 시리즈 기사에서는 EL과 core, fmt, xml, sql 태그 라이브러리에 대해 설명하고 있다.
마지막의 xml, sql 라이브러리는 MVC모델에서 Model측(business logic)의 기능에 가까우므로 제대로 된 대형 프로젝트에서는 사용하지 않도록 해야 겠다.
JSTL을 사용하는 이유는 JSP파일에서 모든 자바코드를 제거하는데 있다.
이는 자바코드 부분을 JSTL태그로 대체하여 유지보수를 용이하게 함에 있다.
[Expression Language(EL)]
JSTL의 EL 예제: ${...}
<c:out value="Hong Gildong"/> <1-- 정적 텍스트로 처리 --> <c:out value="${user.firstName}"/> <!-- EL --> <c:out value="Hello ${user.firstName} ${user.lastName}"/> <!-- 결합된 EL -->
Identifier: user Accessor : firstName, lastName: Literal : "Hello"
Identifier를 찾는 순서 (위의 예에서 user에 해당하는 부분)
내장객체(EL Implicit Object)
Category |
Identifier |
Description |
JSP |
pageContext |
The PageContext instance corresponding to the processing of the current page |
Scopes |
pageScope |
A Map associating the names and values of page-scoped attributes |
requestScope |
A Map associating the names and values of request-scoped attributes |
sessionScope |
A Map associating the names and values of session-scoped attributes |
applicationScope |
A Map associating the names and values of application-scoped attributes |
Request parameters |
param |
A Map storing the primary values of the request parameters by name |
paramValues |
A Map storing all values of the request parameters as String arrays |
Request headers |
header |
A Map storing the primary values of the request headers by name |
headerValues |
A Map storing all values of the request headers as String arrays |
Cookies |
cookie |
A Map storing the cookies accompanying the request by name |
Initialization parameters |
initParam |
A Map storing the context initialization parameters of the Web application by name |
범위변수(Scoped variables) 내부적으로 pageContext의 findAttribute() 메소드를 사용하여 해당 ID를 검색 page request session application
Accessors 객체의 속성(property)를 가져올 때는 dot(.)을 사용 ${user.name} : 자바빈즈의 규칙을 따르므로 getFirstName()메소드가 제공되어야 함. ${user.addresss.city}
배열이나 컬렉션의 원소를 가져올 때는 []를 사용 ${urls[3]} : 배열, 순서화된 컬렉션(java.util.List와 같은) ${commands["dir"]} : java.util.Map ${url[3].protocol}
.과 []는 서로 interchangeable함. ${user["firstName"]} : user객체의 firstName속성값. 즉, ${user.firstName}의 결과와 동일 ${commands.dir} : commands맵의 dir키값. 즉, ${commands["dir"]}의 결과와 동일
연산자(Operators)
The EL operators
Category |
Operators |
Arithmetic |
+ , - , * , / (or div ), % (or mod ) |
Relational |
== (or eq ), != (or ne ), < (or lt ), > (or gt ), <= (or le ), >= (or ge ) |
Logical |
&& (or and ), || (or or ), ! (or not ) |
Validation |
empty |
${ item.price * (1 + taxRate[user.address.zipcode]) } ${ (x >= min) && (x <= max) } ${empty input} : null값, 컬렉션이나 배열의 원소가 없을때, String 길이가 0
연산자 우선순위
[] , . |
() |
unary - , not , ! , empty |
* , / , div , % , mod |
+ , binary - |
() < , > , <= , >= , lt , gt , le , ge |
== , != , eq , ne |
&& , and |
|| , or |
사용 예제)
page범위변수 user에 대해 값을 set/get하는 예제
[User.java] package beans;
public class User { private String firstName; private String lastName; public String getFirstName() { return firstName; } public void setFirstName(String firstName) { this.firstName = firstName; } public String getLastName() { return lastName; } public void setLastName(String lastName) { this.lastName = lastName; } }
[index.jsp] <html> <body> <c:out value="Hong Gildong"/><br/>
<jsp:useBean id="user" class="beans.User" scope="page"></jsp:useBean> <jsp:setProperty name="user" property="firstName" value="Hong"/> <jsp:setProperty name="user" property="lastName" value="Gildong"/>
<c:out value="${user.firstName}"/><br/> <c:out value="Hello ${user.firstName} ${user.lastName}"/><br/>
</body> </html>
[WEB-INF/web.xml]
[header.jsp]
[core 태그 라이브러리의 주요 태그들]
범위변수의 생성/초기화(set)
<c:set var="name" scope="page" value="Hong Gildong"/> <c:out value="${name}"/><br/><br/> <c:remove var="name" scope="page"/>
<c:set var="timezone" scope="session" value="CST"/> <c:set var="squre" value="${param['x'] * param['x']}"/>
<c:set var="timezone" scope="session" value="CST"/>
이것은 아래와 같이 해도 동일하다.
<c:set var="timezone" scope="session">CST</c:set>
출력(out)
Syntax for the <c:out> action <c:out value="expression" default="expression" escapeXml="boolean"/>
default: value가 null이거나 빈 문자열일 경우 대신 출력됨. 사용자가 로그인하면 사용자명을, 로그인 전이면 Guest를 출력한다면 아래와 같이 할 수 있다. Hello <c:out value="${user.username}" default=="Guest"/>!
* <c:set>과 <c:out>의 조합 디폴트값으로 변수를 초기화할 때는 아래와 같은 방식을 사용할 수 있다. timezone변수가 존재하지 않으면 쿠키가 생성될 때 같이 값이 설정된다.
<c:set var="timezone" scope="session"> <c:out value="${cookie['tzPref'].value}" default="CST"/> </c:set>
마지막으로 jsp스크립트를 사용한 아래의 예를 jstl EL코드로 변경한 예를 보였다.
JSP코드 <% if(user.getRole() == "member") { %> <p>Welcome, member!</p> <% } else { %> <p>Welcome, guest!</p> <% } %>
JSTL EL코드 <c:choose> <c:when test="${user.role == 'member'}"> <p>Welcome, member!</p> </c:when> <c:otherwise> <p>Welcome, guest!</p> </c:otherwise> </c:choose>
반복문(forEach, forTokens)
<c:forEach var="name" items="expression" varStatus="name"
begin="expression" end="expression" step="expression">
body content
</c:forEach>
|
Syntax for iterating through a string's tokens with the <c:forTokens> action
<c:forTokens var="name" items="expression"
delims="expression" varStatus="name"
begin="expression" end="expression" step="expression">
body content
</c:forTokens>
|
Collections supported by the items attribute of the <c:forEach> tag
Value for items |
Resulting item values |
java.util.Collection |
Elements from call to iterator() |
java.util.Map |
Instances of java.util.Map.Entry |
java.util.Iterator |
Iterator elements |
java.util.Enumeration |
Enumeration elements |
Array of Object instances |
Array elements |
Array of primitive values |
Wrapped array elements |
Comma-delimited String |
Substrings |
javax.servlet.jsp.jstl.sql.Result |
Rows from an SQL query |
Properties of the LoopTagStatus object
Property |
Getter |
Description |
current |
getCurrent() |
The item (from the collection) for the current round of iteration |
index |
getIndex() |
The zero-based index for the current round of iteration |
count |
getCount() |
The one-based count for the current round of iteration |
first |
isFirst() |
Flag indicating whether the current round is the first pass through the iteration |
last |
isLast() |
Flag indicating whether the current round is the last pass through the iteration |
begin |
getBegin() |
The value of the begin attribute |
end |
getEnd() |
The value of the end attribute |
step |
getStep() |
The value of the step attribute |
* 10사이의 짝수의 제곱을 구함 <c:forEach var="x" begin="0" end="10" step="2"> <c:out value="${x} * ${x} = ${x*x}"/><br/> </c:forEach>
* TP헤더를 출력(Map컬렉션) <c:forEach var="x" items="${header}" varStatus="status"> <c:out value="${status.count}. "/> <c:out value="${x}"/><br/> </c:forEach>
* 콤마가 delimeter인 문자열 출력 <c:set var="fruits" value="banana,apple,tomato,melon"/> <c:forEach var="x" items="${fruits}" varStatus="status"> <c:out value="${x}"/><br/> </c:forEach>
* delimiter가 콤마가 아니라면 forTokens를 사용 <c:set var="fruits" value="banana|apple|tomato|melon"/> <c:forTokens var="x" items="${fruits}" varStatus="status" delims="|"> <c:out value="${x}"/><br/> </c:forTokens>
조건문(if, choose)
Syntax for the <c:if> conditional action
<c:if test="expression" var="name" scope="scope">
body content
</c:if>
|
Syntax for the <c:choose> action
<c:choose>
<c:when test="expression">
body content
</c:when>
...
<c:otherwise>
body content
</c:otherwise>
</c:choose>
|
<c:forEach var="x" items="${header}" varStatus="status"> <c:if test="${status.first}"> <c:out value="[HTTP Header]"/><br/> </c:if> <c:out value="${status.count}. "/> <c:out value="${x}"/><br/> </c:forEach>
<c:choose> <c:when test="${pageContext.request.scheme eq 'http'}"> This is an insecure Web session. </c:when> <c:when test="${pageContext.request.scheme eq 'https'}"> This is an secure Web session. </c:when> <c:otherwise> You are using an unrecognized Web protocol. How did this happen? </c:otherwise> </c:choose>
예외 처리(catch) JSP페이지내에서 예외를 처리할 때. 태그내 'body content'에서 발생한 예외는 JSP에러 메카니즘에서 무시되고 var에 저장된다.
Syntax for the <c:catch> action
<c:catch var="name">
body content
</c:catch>
|
URL처리(url)
Syntax for the <c:url> action
<c:url value="expression" context="expression"
var="name" scope="scope">
<c:param name="expression" value="expression"/>
...
</c:url>
| <a href="<c:url value='/content/sitemap.jsp'/>">View Sitemap</a>
<c:url value="/content/search.jsp"> <c:param name="keyword" value="${searchTerm}}"/> <c:param name="month" value="02/2003"/> </c:url>
var이 지정되면 화면에 출력하지 않고 이 변수에 내용이 저장됨
<c:url var="myURL" value="/content/search.jsp"> <c:param name="keyword" value="${searchTerm}}"/> <c:param name="month" value="02/2003"/> </c:url> <c:out value="${myURL}"/>
컨텐트를 임포트(import)
Syntax for the <c:import> action
<c:import url="expression" context="expression"
charEncoding="expression" var="name" scope="scope">
<c:param name="expression" value="expression"/>
...
</c:import>
|
include directive : jsp페이지가 컴파일될때 포함됨 <jsp:include> : jsp페이지가 호출될 포함됨 <c:import> : jsp페이지가 호출될 포함됨. <jsp:include>의 확장판으로 외부의 리소스까지 include할 수 있다.
var이 지정되면 화면에 출력하지 않고 이 변수에 내용이 저장됨
요청을 리다이렉트(redirect) javax.servlet.http.HttpServletResponse의 sendRedirect()메소드와 동일
Syntax for the <c:import> action
<c:import url="expression" context="expression"
charEncoding="expression" var="name" scope="scope">
<c:param name="expression" value="expression"/>
...
</c:import>
|
* forward, redirect의 차이 forward는 서버측에서 처리되고, redirect는 브라우저에서 처림됨 redirect는 유저의 브라우저에 변경된 주소가 표시되지만, forward는 표지되지 않는다. forward가 좀 더 유용해 보이지만, 현재의 서블릿 컨텍스트내에서만 포워딩이 가능하다는 제한이 있다.
[fmt 태그 라이브러리의 주요 태그들]
Localization context tags(setLocale, setTimeZone, timeZone) 데이터 지역화(Localization)에 영향을 주는 요소: locale, timezone
데스크탑 자바 애플리케이션은 VM이 OS를 통해 디폴트 locale, timezone을 파악하지만, 서버측 자바 애플리케이션은 서버보다는 클라이언트측 정보에 의존해야 하므로 다음과 같은 순서로 locale,timezone을 결정한다.
1. JSP 설정변수
<fmt:setLocale value="expression" scope="scope" variant="expression"/>
|
value: 로케일명 or java.util.Locale 로케일명: ISO 언어코드+국가코드로 구성(국가코드는 옵션) 언어코드 목록: ISO 639 specification ( http://www.loc.gov/standards/iso639-2/englangn.html) 국가코드 목록: ISO 3166 specification ( http://userpage.chemie.fu-berlin.de/diverse/doc/ISO_3166.html) ex) ko_KR, en_US, fr_CA, ko, en, fr, ... scope: page, request, session, application variant: MAC, WIN,..
<fmt:setTimeZone value="expression" var="name" scope="scope"/>
| value: 타임존명 or java.util.TimeZone var: 인스턴스화된 timezone값이 var에 저장되고, 현재의 타임존은 변화 없음 사용가능한 타임존명 파악 String[] ids = java.util.TimeZone.getAvailableIDs(); for(String id : ids) System.out.println(id); 현재의 타임존 파악 System.out.println(java.util.TimeZone.getDefault()); // sun.util.calendar.ZoneInfo[id="Asia/Seoul",offset=32400000,dstSavings=0,useDaylight=false,transitions=14,lastRule=null]
<fmt:timeZone value="expression">
body content
</fmt:timeZone>
| setTimeZone과 같으나, body content내에서만 유효함. 예) default locale, timezone의 지정
<fmt:setLocale value="ko_KR: scope="session"/> <fmt:setTimezone value="Asia/Seoul" scope="session"/>
2. HTTP프로토콜의 Accept-Language헤더값으로 locale 파악 (timezone 정보는 파악이 불가능) accept-language=ko accept-language=en,ko;q=0.5 * 이는 javax.servlet.ServletRequest클래스의 getLocale(), getLocales()를 통해서 자동으로 파악됨.
3. VM default locale (JSP컨테이너가 위치한 OS에서 파악)
Date tags(formatDate, parseDate)
<fmt:formatDate value="expression"
timeZone="expression"
type="field" dateStyle="style"
timeStyle="style"
pattern="expression"
var="name" scope="scope"/>
|
type: time, date, both dateStyle, timeStyle: default, short, medium, long, full pattern: dateStyle,timeStyle 대신 사용자가 지정 java.text.SimpleDateFormat에 따른 패턴으로 지정. 예) MM/dd/yyyy
[User.java] package beans; import java.util.*; public class User { private Date birth = new Date(); public Date getBirth() { return birth; } .... }
[index.html] <jsp:useBean id="user" class="beans.User" scope="page"/> <c:out value="${user.birth}"/><br/> <fmt:formatDate value="${user.birth}"/><br/> <fmt:formatDate value="${user.birth}" type="both"/><br/> <fmt:formatDate value="${user.birth}" type="both" dateStyle="full" timeStyle="full" /><br/> <fmt:formatDate value="${user.birth}" pattern="yyyy/MM/dd hh:mm:ss" /><br/>
결과: Sun Aug 20 21:16:01 KST 2006 2006. 8. 20 2006. 8. 20 오후 9:16:01 2006년 8월 20일 일요일 오후 9시 16분 01초 KST 2006/08/20 09:16:01
<fmt:parseDate value="expression"
type="field" dateStyle="style" timeStyle="style"
pattern="expression"
timeZone="expression" parseLocale="expression"
var="name" scope="scope"/>
<fmt:parseDate
type="field" dateStyle="style" timeStyle="style"
pattern="expression"
timeZone="expression" parseLocale="expression"
var="name" scope="scope">
body content
</fmt:parseDate>
| 주어진 문자열을 java.util.Date형으로 변환. 사용할 이유 없음. 차라리 서블릿에서 처리하는 것이 적합
<c:set var="koDateString">06. 4. 1 오후 7:03</c:set> <fmt:parseDate value="${koDateString}" parseLocale="ko_KR" type="both" dateStyle="short" timeStyle="short" var="koDate"/>
<c:set var="usDateString">4/1/06 7:03 PM</c:set> <fmt:parseDate value="${usDateString}" parseLocale="en_US" type="both" dateStyle="short" timeStyle="short" var="usDate"/>
<c:set var="gbDateString">4/1/06 19:03</c:set> <fmt:parseDate value="${gbDateString}" parseLocale="en_GB" type="both" dateStyle="short" timeStyle="short" var="gbDate"/>
<table border="1"> <tr> <th>Locale</th> <th>input</th> <th>output</th> </tr> <tr> <td>Korea Korean(ko_KR)</td> <td><c:out value="${koDateString}"/></td> <td><c:out value="${koDate}"/></td> </tr> <tr> <td>U.S. English(en_US)</td> <td><c:out value="${usDateString}"/></td> <td><c:out value="${usDate}"/></td> </tr> <tr> <td>British English(en_GB)</td> <td><c:out value="${gbDateString}"/></td> <td><c:out value="${gbDate}"/></td> </tr>
결과:
Locale |
input |
output |
Korea Korean(ko_KR) |
06. 4. 1 오후 7:03 |
Sat Apr 01 19:03:00 KST 2006 |
U.S. English(en_US) |
4/1/06 7:03 PM |
Sat Apr 01 19:03:00 KST 2006 |
British English(en_GB) |
4/1/06 19:03 |
Wed Jan 04 19:03:00 KST 2006 |
Number tags(formatNumber, parseNumber)
숫자라는 차이외엔 formatDate, parseDate와 유사
<fmt:formatNumber value="expression"
type="type" pattern="expression"
currencyCode="expression" currencySymbol="expression"
maxIntegerDigits="expression" minIntegerDigits="expression"
maxFractionDigits="expression" minFractionDigits="expression"
groupingUsed="expression"
var="name" scope="scope"/>
|
type: number, currency, percentage currentCode: type이 currency일때 유효. 통화기호를 ISO통화코드에서 정의한 코드로 지정 통화코드 목록: ISO 4217 specification ( http://www.xe.com/iso4217.htm) * 한국: KRW Korea (South), Won currentSymbol: type이 currency일때 유효. 통화기호를 사용자가 지정 maxIntegerDigits,minIntegerDigits,maxFractionDigits,minFractionDigits: 정소, 소수 부분 자리수 지정 groupingUsed: boolean값. 자리수 표시 토글(default: true)
화폐 단위 예제
<fmt:setLocale value="ko_KR"/> <fmt:formatNumber value="200000" type="currency"/>
결과: ₩200,000
<fmt:parseNumber value="expression"
type="type" pattern="expression"
parseLocale="expression"
integerOnly="expression"
var="name" scope="scope"/>
<fmt:parseNumber
type="type" pattern="expression"
parseLocale="expression"
integerOnly="expression"
var="name" scope="scope">
body content
</fmt:parseNumber>
| 주어진 문자열을 java.util.Number형으로 변환. 사용할 이유 없음. 차라리 서블릿에서 처리하는 것이 적합
Message tags(setBundle, bundle, message, param)
로케일과 연관된 리소스 번들에서 문자열 메시지를 가져옴
<fmt:setBundle basename="expression"
var="name" scope="scope"/>
|
<fmt:bundle basename="expression"
prefix="expression">
body content
</fmt:bundle>
|
<fmt:message key="expression" bundle="expression"
var="name" scope="scope"/>
<fmt:message key="expression" bundle="expression"
var="name" scope="scope">
<fmt:param value="expression"/>
...
</fmt:message>
| setBundle이나 bundle(일시적으로 사용시)로 리소스 번들파일을 지정한 뒤,
message태그를 사용하여 메시지를 표시하거나 변수에 저장한다.
[a.txt] test.Greeting.greeting=안녕하세요 {0}씨, JSTL 블로그에 오신걸 환영합니다.
[WEB-INFclassesGreeting_en.properties] test.Greeting.greeting=Hello {0}, and welcome to the JSTL Blog.
[WEB-INFclassesGreeting_ko.properties] - a.txt에 대해 native2ascii를 수행한 결과 test.Greeting.greeting=uc548ub155ud558uc138uc694 {0}uc528, JSTL ube14ub85cuadf8uc5d0 uc624uc2e0uac78 ud658uc601ud569ub2c8ub2e4.
[index.jsp] <fmt:bundle basename="Greeting"> <fmt:message key="test.Greeting.greeting"> <fmt:param value="홍길동"/> </fmt:message> </fmt:bundle>
[index.jsp] - prefix를 사용한 예제(출력은 위의 예제와 동일) <fmt:bundle basename="Greeting" prefix="test.Greeting."> <fmt:message key="greeting"> <fmt:param value="홍길동"/> </fmt:message> </fmt:bundle>
결과: 안녕하세요 홍길동씨, JSTL 블로그에 오신걸 환영합니다.
[index.jsp] - 영어로 출력 테스트
<fmt:setLocale value="en_US"/> <fmt:bundle basename="Greeting" prefix="test.Greeting."> <fmt:message key="greeting"> <fmt:param value="Hong Gildong"/> </fmt:message> </fmt:bundle>
결과:
Hello Hong Gildong, and welcome to the JSTL Blog.
[xml 태그 라이브러리의 주요 태그들] - parse, transform
<x:parse xml="expression" var="name" scope="scope"
filter="expression" systemId="expression"/>
|
<x:parse var="name" scope="scope"
filter="expression" systemId="expression">
body content
</x:parse>
|
<x:parse xml="expression" varDom="name" scopeDom="scope"
filter="expression" systemId="expression"/>
|
<x:parse varDom="name" scopeDom="scope"
filter="expression" systemId="expression">
body content
</x:parse>
|
Interaction of the <x:parse> and <c:import> actions
<c:import var="rssFeed" url="http://slashdot.org/slashdot.rdf"/>
<x:parse var="rss" xml="${rssFeed}"/>
|
<x:transform xml="expression" xslt="expression"
var="name" scope="scope"
xmlSystemId="expression" xsltSystemId="expression">
<x:param name="expression" value="expression"/>
...
</x:transform>
|
<x:transform xslt="expression"
var="name" scope="scope"
xmlSystemId="expression" xsltSystemId="expression">
body content
<x:param name="expression" value="expression"/>
...
</x:transform>
|
Syntax variations for the <x:transform> action when using the result attribute to supply a javax.xml.transform.Result instance
<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>
|
core라이브러리의 태그와 유사한 태그들 <x:set> <x:if> <x:choose>, <x:when>, <x:otherwise> <x:forEach>
[index.jsp]<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}"/>
[WEB-INF/xslt/rss2html.xsl]
<?xml version="1.0"?> <xsl:stylesheet xmlns:xsl=" http://www.w3.org/1999/XSL/Transform" version="1.0"> <xsl:template match="/"> <a> <xsl:attribute name="href"> <xsl:value-of select="//*[name()='channel']/*[name()='link']"/> </xsl:attribute> <xsl:value-of select="//*[name()='channel']/*[name()='title']"/> </a> <ul> <xsl:for-each select="//*[name()='item']"> <li> <a> <xsl:attribute name="href"> <xsl:value-of select="./*[name()='link']"/> </xsl:attribute> <xsl:value-of select="./*[name()='title']"/> </a> </li> </xsl:for-each> </ul> </xsl:template> </xsl:stylesheet>
결과: <x:out>의 select에는 XPath표현식을 사용하면 된다고 했지만, 실제 테스트해보니 제대로 되지 않음. 파악하는데 시간낭비될 것 같아 다음에 알아볼 것임.
<x:out>테스트<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"/>
<a href="<x:out select="$rss//*[name()='channel']/*[name()='link'][1]"/>" ><x:out select="$rss//*[name()='channel']/*[name()='title'][1]" escapeXml="false"/></a>
<ul> <x:forEach select="$rss//*[name()='item']"> <li> <a href="<x:out select="./*[name()='link']"/>" ><x:out select="./*[name()='title']" escapeXml="false"/></a> </x:forEach> </ul>
[sql 태그 라이브러리의 주요 태그들] setDataSource, query, update, transaction
<sql:setDataSource dataSource="expression"
var="name" scope="scope"/>
<sql:setDataSource url="expression" driver="expression"
user="expression" password="expression"
var="name" scope="scope"/>
| dataSource: JNDI명 url: JDBC URL
위 2가지 형태중 아무거나 사용할 수 있으나, 막코딩(hard-coding)나 테스트 용도가 아니라면 대개 1번째 형태를 사용할 것이다.
하지만, 사실 위의 형태보다는 web.xml에 디폴트를 지정하는 것이 보다 일반적일 것이다. 아래와 같다.
Using a JNDI name to set JSTL's default datasource in the web.xml deployment descriptor
<context-param>
<param-name>javax.servlet.jsp.jstl.sql.dataSource</param-name>
<param-value>jdbc/blog</param-value>
</context-param>
|
SQL문에 따라, 데이터 변경이 필요하면 update태그를, 단순 조회용이면 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>
|
maxRows: 반환되는 행의 최대 개수 startRows: 처음에서 skip될 행 개수
쿼리의 실행결과(var에 저장됨)는 javax.servlet.jsp.jstl.sql.Result 인터페이스의 인스턴스로 범위변수(scoped variable)에 저장된다.
Properties defined by the javax.servlet.jsp.jstl.sql.Result interface
Property |
Description |
rows |
An array of SortedMap objects, each of which maps column names to a single row in the result set |
rowsByIndex |
An array of arrays, each corresponding to a single row in the result set |
columnNames |
An array of strings naming the columns in the result set, in the same order as used for the rowsByIndex property |
rowCount |
The total number of rows in the query result |
limitedByMaxRows |
True if the query was limited by the value of the maxRows attribute |
Using <sql:query> to query a database, and using <c:forEach> to iterate through the result set
<sql:setDataSource var="dataSrc" url="jdbc:oracle:thin:@localhost:1521:ORCL" driver="oracle.jdbc.OracleDriver" user="scott" password="tiger"/>
<sql:query var="queryResults" dataSource="${dataSrc}"> select * from emp where rownum < ? <sql:param value="${6}"/> </sql:query>
<table border="1"> <tr> <th>EMPNO</th> <th>ENAME</th> <th>JOB</th> <th>MGR</th> <th>HIREDATE</th> <th>SAL</th> <th>COMM</th> <th>DEPTNO</th> </tr> <c:forEach var="row" items="${queryResults.rows}"> <tr> <td><c:out value="${row.empno}"/></td> <td><c:out value="${row.ename}"/></td> <td><c:out value="${row.job}"/></td> <td><c:out value="${row.mgr}"/></td> <td><c:out value="${row.hiredate}"/></td> <td><c:out value="${row.sal}"/></td> <td><c:out value="${row.comm}"/></td> <td><c:out value="${row.deptno}"/></td> </tr> </c:forEach>
| 결과:
EMPNO |
ENAME |
JOB |
MGR |
HIREDATE |
SAL |
COMM |
DEPTNO |
7369 |
SMITH |
CLERK |
7902 |
1980-12-17 |
800 |
20 |
7499 |
ALLEN |
SALESMAN |
7698 |
1981-02-20 |
1600 |
300 |
30 |
7521 |
WARD |
SALESMAN |
7698 |
1981-02-22 |
1250 |
500 |
30 |
7566 |
JONES |
MANAGER |
7839 |
1981-04-02 |
2975 |
20 |
7654 |
MARTIN |
SALESMAN |
7698 |
1981-09-28 |
1250 |
1400 |
30 |
패러미터가 날짜/시간의 값을 가진다면, param태그 대신 datePram태그를 사용한다.
<sql:dateParam value="expression" type="type"/>
| value: java.util.Date type: date | time | timestamp
<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>
|
var이 지정되면, java.lang.Integer형으로 저장되며, 갱신된 행의 개수를 나타낸다.
<sql:transaction dataSource="expression" isolation="isolationLevel">
<sql:query .../> or <sql:update .../>
...
| dataSource: 지정하지 않으면, JSTL 디폴트 데이터소스를 사용 isolation: read_committed, read_uncommitted , repeatable_read , serializable
transaction내에 내포된 query, update태그는 transaction태그의 데이터소스를 사용하므로, dataSources속성값은 의미가 없다.
Using <sql:transaction> to combine database updates into a transaction
<html> <body>
<sql:setDataSource var="dataSrc" url="jdbc:oracle:thin:@localhost:1521:ORCL" driver="oracle.jdbc.OracleDriver" user="scott" password="tiger"/>
<sql:transaction dataSource="${dataSrc}"> <sql:update sql="insert into dept(deptno, dname, loc) values(?,?,?)"> <sql:param value="50"/> <sql:param value="DEVS"/> <sql:param value="SEOUL"/> </sql:update> <sql:update sql="update dept set LOC=? where deptno=?"> <sql:param value="BUSAN"/> <sql:param value="50"/> </sql:update> </sql:transaction>
</body> </html>
|
위와 같이 데이터소스를 명시적으로 지정하기 보다는 디폴트 데이터소스를 사용하는 것이 보다 일반적일 것이다. 그러면 JSP페이지에서는 데이터소스를 명시적으로 지정할 필요없이 query나 update태그를 바로 사용할 수 있다.
[WEB-INF/web.xml]<?xml version="1.0" encoding="UTF-8"?> <web-app id="WebApp_ID" version="2.4" xmlns=" http://java.sun.com/xml/ns/j2ee" xmlns:xsi=" http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=" http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"> <welcome-file-list> <welcome-file>index.jsp</welcome-file> </welcome-file-list> <jsp-config> <jsp-property-group> <url-pattern>*.jsp</url-pattern> <el-ignored>false</el-ignored> <page-encoding>euc-kr</page-encoding> <scripting-invalid>false</scripting-invalid> <include-prelude>/header.jsp</include-prelude> </jsp-property-group> </jsp-config> <context-param> <param-name>javax.servlet.jsp.jstl.sql.dataSource</param-name> <param-value>jdbc/OracleDB</param-value> </context-param>
</web-app>
[META-INF/context.xml] - 톰캣 JNDI 설정 <?xml version="1.0" encoding="euc-kr" ?> <Context> <Resource name="jdbc/OracleDB" auth="Container" type="javax.sql.DataSource" username="scott" password="tiger" driverClassName="oracle.jdbc.OracleDriver" url="jdbc:oracle:thin:@localhost:1521:ORCL"/> </Context>
[index.html] <html> <body>
<sql:transaction> <sql:update sql="insert into dept(deptno, dname, loc) values(?,?,?)"> <sql:param value="50"/> <sql:param value="DEVS"/> <sql:param value="SEOUL"/> </sql:update> <sql:update sql="update dept set LOC=? where deptno=?"> <sql:param value="BUSAN"/> <sql:param value="50"/> </sql:update> </sql:transaction>
</body> </html>
[functions 태그 라이브러리의 주요 태그들]
[index.jsp]
<html> <body>
<c:set var="name" value="Welcome to 한국 "/> <c:set var="name" value="${fn:trim(name)}"/><br/>
<c:out value="name: ${name}"/><br/><br/> <c:out value="length(name): ${fn:length(name)}"/><br/> <c:out value="toUpperCase(name): ${fn:toUpperCase(name)}"/><br/> <c:out value="toLowerCase(name): ${fn:toLowerCase(name)}"/><br/> <c:out value="substring(name,3,7): ${fn:substring(name,3,7)}"/><br/> <c:out value="substringBefore(name,'come'): ${fn:substringBefore(name, 'come')}"/><br/> <c:out value="substringAfter(name,'Welcome'): ${fn:substringAfter(name, 'Welcome')}"/><br/> <c:out value="replace(name, '한국', 'Korea'): ${fn:replace(name, '한국', 'Korea')}"/><br/> <c:out value="indexOf(name, 'to'): ${fn:indexOf(name,'to')}"/><br/> <c:out value="contains(name, 'welcome'): ${fn:contains(name, 'welcome')}"/><br/> <c:out value="containsIgnoreCase(name, 'welcome'): ${fn:containsIgnoreCase(name, 'welcome')}"/><br/> <c:out value="startsWith(name, 'Welcome'): ${fn:startsWith(name, 'Welcome')}"/><br/> <c:out value="endsWith(name, '한국'): ${fn:endsWith(name, '한국')}"/><br/>
<c:remove var="name"/>
<c:out value="---------------------------------"/><br/>
<c:set var="fruits" value="사과,배,참외,수박,복숭아"/>
<c:set var="fruits_arr" value="${fn:split(fruits,',')}"/> <c:forEach var="x" items="${fruits_arr}"> <c:out value="${x}"/><br/> </c:forEach>
<c:out value="${fn:join(fruits_arr, ',')}"/><br/>
</body> </html>
결과:
name: Welcome to 한국
length(name): 13 toUpperCase(name): WELCOME TO 한국 toLowerCase(name): welcome to 한국 substring(name,3,7): come substringBefore(name,'come'): Wel substringAfter(name,'Welcome'): to 한국 replace(name, '한국', 'Korea'): Welcome to Korea indexOf(name, 'to'): 8 contains(name, 'welcome'): false containsIgnoreCase(name, 'welcome'): true startsWith(name, 'Welcome'): true endsWith(name, '한국'): true --------------------------------- 사과 배 참외 수박 복숭아 사과,배,참외,수박,복숭아
|