JSTL - functions - core, fn, fmt, xml

Posted 11 19, 2009 17:26, Filed under: Language/ㅡ Jsp

자료 출처 : http://pupustory.tistory.com/


J2EE의 표현 계층(presentation layer)인 JSP에서 코드가 삽입되는건 당연한 일이다. MVC를 이용한 경우 컨트롤러에서 비지니스 로직의 처리가 끝나고, 사용자에게 정보를 표시해 줄 때 형식을 맞춰 HTML로 출판해 줘야 하니 말이다.

일반적으로 JSP는 <% .. %>의 스크립틀릿을 써왔다. 컨트롤러에서 속성으로 넘어온 정보를 받아 목록을 표시하는 일반적인 CRUD화면을 개발해 본 사람이라면 대부분 그러할 것 이다. 물론 이것이 문제가 되는건 아니다. 어차피 servlet로 작성되니 말이다. 여기서 JSTL을 이용하면 얻는 이점은 다음과 같다.


첫째. 편리한 유지보수
예를들어 디자인이 변경되었다고 가정해 보자. css만 변경된거라면 큰 불편이 없겠지만, 디자인 전체가 바뀌었고, 표현 방식이 바뀌었다면 디자이너에게 페이지를 다시 받아 거기에 추가해 넣어야 하는데, 이건 HTML과 코드가 뒤섞여 가독성에 문제가 될 수 있다.

둘째. 디자이너가 작성된 페이지(JSP)에 거부감이 없어짐
JSTL은 xml과 매우 흡사하다. 다시말해 디자이너가 알고있는 html 코드와 흡사하다는 얘기다. 따라서 개발중인 페이지에 디자인이 변경 되어도, 디자이너는 구체적 내용은 모르지만 기존의 코드가 섞인 페이지보다 쉽게 수정할 수 있다.(대부분 여기선 개발자가 알아서 했을 경우가 많지만..)

설치방법
1. JSTL 관련 라이브러리를 다운로드
2. 프로젝트에 JSTL라이브러리 추가

추가 라이브러리 보기

그럼 가장 간단한 페이지 소스를 보고 JSTL을 이용한 예제를 확인하자.
  1. <%@ page language="java" contentType="text/html; charset=UTF-8"    pageEncoding="UTF-8"%>    <!-- jstl 사용을 위한 테그 라이브러리 선언 --><%@ taglib prefix="c"   uri="http://java.sun.com/jsp/jstl/core" %> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"     "http://www.w3.org/TR/html4/loose.dtd"><html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><title>JSTL</title></head><body><p> requestScope : </p><c:out value="${requestScope.stat}" /><p> sessionScope : </p><c:out value="${sessionScope.stat}"/><br /> end line.</body></html>  


상단에 선언한 것은 JSTL중 core부분을 사용하겠다는 얘기다. 이것 외에도 여러가지 JSTL 테그들이 있는데 그것은 차후 살펴보기로 하겠다.
<c:out value="${requestScope.stat}" />

간단하게 출력하는 구문이다. value부분은 EL을 이용한것인데, request의 애트리뷰트 'stat'의 값을 받아와 출력한다는 의미다. 즉 이전의 컨트롤러에서 request.setAttribute("stat","value!"); 의 설정을 했다면 여기서 value!가 출력될 것이다.

Category 식별자 설명
JSP pageContext 현재 페이지의 프로세싱과 상응하는 PageContext 인스턴스
범위 pageScope 페이지 범위 애트리뷰트 이름과 값과 관련된 Map
requestScope 요청 범위 애트리뷰트 이름과 값과 관련된 Map
sessionScope 세션 범위 애트리뷰트 이름과 값과 관련된 Map
applicationScope 애플리케이션 범위 애트리뷰트 이름과 값과 관련된 Map
요청 매개변수 param 요청 매개변수의 기본 값을 이름으로 저장하는 Map
paramValues 요청 매개변수의 모든 값을 String 어레이로서 저장하는 Map
요청 헤더 header 요청 헤더의 기본 값을 이름으로 저장하는 Map
headerValues 요청 헤더의 모든 값을 String 어레이로서 저장하는 Map
쿠키 cookie 요청에 수반되는 쿠키들을 이름으로 저장하는 Map
초기화 매개변수 initParam 웹 애플리케이션의 콘텍스트 초기화 매개변수를 이릉으로 저장하는 Map
<IBM 참조>

EL을 이용해 사용할 수 있는 것들이다. 요청 매개변수는 흔히 사용하는 getParameter() 부분이다. 이것음 ${param.parameter}로 이용하는데 위와같이 사용하려면 아래와 같다.
<c:out value="${param.stat}" />

보는김에 EL을 좀 더 살펴보자. EL은 연산도 가능하다.

Category 연산자
산술 +, -, *, / (or div), % (or mod)
관계형 == (or eq), != (or ne), < (or lt), > (or gt), <= (or le), >= (or ge)
논리 && (or and), || (or or), ! (or not)
타당성검사 empty
<IBM 참조>

  1. <c:out value="${param.value1 + param.value2}" />  


이번엔 core의 변수 설정 방법을 이용해 보자.
  1. <c:set var="var" value="${param.stat}" /><c:out value="${var}" default="var is null !"/>  


var은 변수명이다. 파라미터로 넘어온 값을 EL로 받아 value에 설정했다. 그다음 바로 출력한다. 이때 위에 설정한 변수를 찾아 출력하면 된다. 여기서 default는 변수가 null일경우 출력된다. EL에서 null값은 별도의 Exception이 발생하지 않는다. 따라서 디버깅을 할땐 저런 방식을 이용하는게 좋을듯 하다.

변수 해제는 <c:remove />를 이용하면 된다.
  1. <c:set var="var" value="${param.stat}" /><c:out value="${var}" default="var is null !"/><c:remove var="var"/><c:out value="${var}" default="var is null !"/>  

stat파라미터를 보내서 테스트 해 보면 처음엔 파라미터값이 출력되고 후엔 remove를 통해 지웠으므로 default가 출력 될 것이다.

EL과 JSTL은 강력하다. 보기에 그리 거부감도 없고, 왠만한 기능을 모두 지원 한다. 최소한 프레젠테이션 계층에서 이용되는 부분은 다 있다.(SQL도 가능하니 .. )



------------------------------------------------------------------------

# core
<c:out value="expression" default="expression" escapeXml="boolean"/>
이전 포스트에 살펴본 내용대로 value에는 출력할 내용을. defalut는 value가 null일 경우 출력할 기본 내용을 얘기한다. EL을 이용할 경우 "${}"를 이용할 수 있다. value는 <c:out >value</c:out> 로도 할 수 있다.

<c:set var="expression" scope="request" value="expression"/>
변수를 할당한다. var은 변수명을. scope는 영역을. value는 값이 온다. 앞에서 살펴본 바와 같이 ${} 같은 EL을 사용할 수 있다. <c:out>와 마찬가지로 <c:set var="expression">value !!</c:set>로도 이용할 수 있다.

<c:remove var="expression" scope="request"/>
변수에 할당한 값을 삭제 한다. var는 변수명이 오는데 .. 음.. 그다지 설명할 거리는 없다.

<c:forEach var="name" varStatus="name"
begin="expression" end="expression" step="expression">
body content
</c:forEach>
일반적으로 스크립틀릿을 사용할 경우 <% for (int i=0; i<10;i++) {} %>의 역할을 한다. 이때 주목할 점은 for가 아니라 forEach라는 점이다. JDK5.0에서 추가된 forEach를 이용하는 얘기다. 그렇다고 고전적인 방법(?)을 사용하지 못하는 것은 아니다. forEach를 이용한 방법은 다음과 같다.
  1. <%    
  2.     java.util.List<String> arrayList = new java.util.ArrayList<String>();    
  3.     arrayList.add("pupustory");    
  4.     arrayList.add("yaho");    
  5.     arrayList.add("babo");    
  6.     arrayList.add("hehe");    
  7.     request.setAttribute("lists",arrayList);    
  8. %>  
  9. <c:forEach  items="${requestScope.lists}" var="value">    
  10.     <li><c:out value="${value}"></c:out></li>    
  11. </c:forEach>    

request의 속성에 작성한 ArrayList를 넣어두고, forEach를 통해 하나씩 받아와 value에 저장한다. 총 반복 횟수는 items의 값과 같다. 친절하게도 Iterator, Map, Collection, Enumeration 및 사용자가 작성한 Object[], ','로 구성된 String를 모두 지원 한다. 이번엔 일반적(1.4에서 사용한..)으로 사용했던 방식을 이용해 보자.
  1. <c:forEach begin="0" end="10" step="1">    
  2.     <li><p>pupustory</p></li>    
  3. </c:forEach>    
  4.  
  5. <c:forEach begin="0" end="10" step="1"> <li><p>pupustory</p></li> </c:forEach>  

begin은 초기값, end는 종료값, step는 증가값이다. 별로 어렵지 않다. 마지막으로 varStatus는 내부의 정보(?)를 알려주는 객체를 생성한다. 객체생성후 사용은 EL에 따라 사용한다. 먼저 객체의 속성은 다음과 같다.

속성 Getter Description
current getCurrent() 현재 반복 라운드 아이템
index getIndex() 현재 반복 라운드의 제로 기반(zero-based) 인덱스
count getCount() 현재 반복 라운드의 1 기반(one-based) 인덱스
first isFirst() 현재 라운드가 반복을 통한 첫 번째 패스임을 나타내는 플래그
last isLast() 반복현재 라운드가 반복을 통한 마지막 패스임을 나타내는 플래그
begin getBegin() begin 애트리뷰트의 값
end getEnd() end 애트리뷰트의 값
step getStep() step 애트리뷰트의 값
<IBM 참조>

<c:forTokens var="name" items="expression"
  delims="expression" varStatus="name"
  begin="expression" end="expression" step="expression">
  body content
</c:forTokens>
java에서 흔히 사용한 StringTokenizer이다. 예제는 아래와 같으며 forEach와 마찬가지로 begin, end, step, varStatus가 존재 한다. 사용법은 동일 하다.
  1. <% String str = "a,b,c,d,e,f,g,h,i,j,/k,l,m,n,o,p/,q,r,s,t,u/,v,w,x,y/,z"; %>  
  2. <c:forTokens items="${requestScope.str}" delims="/" var="value">  
  3.     <c:out value="${value}" default="value is nul !!" /><br/>  
  4. </c:forTokens>  

<c:if test="expression" var="name" scope="scope">

  body content
</c:if>
개발 하면서 가장 많이 사용한 구문은 무엇일까 ? for문도 둘째가라면 서러울 정도로 많이 사용하지만 가장 많이 사용하는건 역시 분기기 사용하는 if문이 아닐까 싶다. JSTL은 역시 if문을 사용할 수 있도록 해주고 있다.(사실 이거 없음.. 쩝..)
  1. <%    
  2.     request.setAttribute("isTrue","true");    
  3. %>    
  4. <c:if test="${requestScope.isTrue}"> it's true !</c:if>  

구문은 간단하다. test에 'true'가 들어오면 실행하고 그 외의 것이 들어오면 실행하지 않는다. 엄밀히 따지면 여기엔 true false가 와야 하지만..참 관대하다.

<c:choose>
  <c:when test="expression">
    body content
  </c:when>
  ...
  <c:otherwise>
    body content
  </c:otherwise>
</c:choose>
아쉽게도 위  구문은 별다른 조건을 지원하지 않는다. 때문에 다양한 조건에 대한 분기는 <c:choose />를 사용해야 한다. 조건에 대해선 <c:when test="" />로 구분한다. 물론 test에는 'true'라는 문자열에만 '참'으로 반응 한다. case문에서 사용했던 default는 <c:otherwise />로 이용 한다. 위 when 조건에서 걸리지 않으면 default로 수행 된다.

조건에 만족하지 않고, otherwise가 없다면, 당연히 그 블럭은 아무것도 수행하지 않을 것 이다.
  1. <%  
  2.     request.setAttribute("value","2");  
  3. %>  
  4. <c:choose>  
  5.  <c:when test="${requestScope.value eq '1'}">  
  6.   <c:out value="request 'value' attribute is 1" />  
  7.  </c:when>  
  8.  <c:when test="${requestScope.value eq '2'}">  
  9.   <c:out value="request 'value' attribute is 2" />  
  10.  </c:when>  
  11.  <c:otherwise>  
  12.   <c:out value="request 'value' attribute unknow .." />  
  13.  </c:otherwise>  
  14. </c:choose>  


<c:import url="expression" context="expression"
   charEncoding="expression" var="name" scope="scope">
  <c:param name="expression" value="expression"/>
  ...
</c:import>
템플릿을 이용한 페이지나, 공통으로 들어가는 부분은 별도로 관리해 jsp액션을 이용해 사용한다. JSTL에도 그러한 기능을 제공 한다. url부분에 추가할 페이지를 작성한다. 사용법은 <jsp:include/>와 매우 비슷하다.
  1. <c:import url="http://www.pupustory.com/index.jsp">  
  2.  <c:param name="stat" value="value"></c:param>  
  3. </c:import>  


<c:url value="expression" context="expression"
    var="name" scope="scope">
  <c:param name="expression" value="expression"/>
  ...
</c:url>
URL은 java.net.URL을 이용 한다. 위에서도 url을 속성을 이용했지만, 여기서 기존의 jsp액션과 틀린점은 http프로토콜만 지원하지 않고, import할 수 있는 url은 같은 도메인상에 있지 않아도 되는 것 이다. http가 아닌 ftp의 형식으로도 이용할 수 있다는 얘기다.

<c:catch var="name">
  body content
</c:catch>
JSTL은 위에서 얘기한 대로 별도의 Exception이 발생하지 않는다.(물론 JSTL구문을 제대로 사용하지 않았을 경우 Exception이 발생 한다.) 여기에 도움이 되고자 <c:exception/>이 있다. 하나의 주제로 해서 다루기엔 작은 내용이니 <c:import/>와 같이 알아보도록 하겠다.
  1. <c:catch var="exception">  
  2. <c:import url="http://www.pupustory.co.kr/sample.html">  
  3. <c:param name="stat" value="123" />  
  4. </c:import>  
  5. </c:catch>  
  6. <c:if test="${not empty exception}">  
  7.  <c:out value="exception is not null !"/>  
  8. </c:if>  

import를 수행 하는데 예외가 발생하면 exception객체가 생성 될 것이다. 따라서 null이 아니라면(비어있지 않다면..not empty) 조건을 수행하게 된다.

<c:redirect url="expression" context="expression">
  <c:param name="expression" value="expression"/>
  ...
</c:redirect>
redirect는 별도의 설명이 필요 없는듯 하다. url로 이동 한다. redirect와 forward의 차이점은 이전 포스트에서 참조하도록 하고 .. 직접 사용해 보자.

  1. <c:catch var="exception">  
  2.   <c:import url="http://pupustory.com/not found page error"/>  
  3. </c:catch>  
  4. <c:if test="${not empty exception}">  
  5.   <c:redirect url="http://pupustory.com/error/404.html"/>  
  6. </c:if>  

사실 error페이지는 지시어를 통해 하는 경우가 많다. 이것은 조건에 따라 분기를 한다는 것에 촛점을 맞춰야 할 듯 하다.지금까지 알아본 JSTL core부분은 실무에서 가장 많이 쓰는 부분이 아닐까 싶다. 사실 이정도 조건이면 어지간한 화면은 구성될 듯 하다.


------------------------------------------------------------------------

# fn

JSTL은 JSP에서 <% %>같은 자바 코드를 빼자는 취지에서 태어났으므로 위와같은 문제점에 대응할 해결책이 있다. 그것이 바로 functions이다. 여기엔 보편적으로 많이 사용하는 유용한 유틸들을 모아두었다.(JSTL이라지만.. 이건 EL이 아닐까 ..싶다. EL인가?) java에서 많이 사용하던 부분이므로 구체적인 설명은 빼고 살펴보겠다. 먼저 tlb 지시어는 다음과 같다.
  1. <%@ taglib prefix="fn"   
  2.     uri="http://java.sun.com/jsp/jstl/functions" %>  

* 중요 *
$(fn}안에선 ${}을 통한 변수 접근이 불가능 하다. 따라서 ${fn:substring(${requestScope.str},"yaho")}는 반드시 ${fn:substring(requestScope.str,"yaho")}로 사용해야 한다.

${fn:substring(expression, start, end)}
start에서 end까지의 인덱스만큼 문자를 가져온다. EL이므로 별도의 exception은 발생하지 않는다. 일반적으로 java로 사용 할 경우 "pupustory".substring(1,50)는 문제가 발생 할 것이다. 하지만 여기선 없음 없는데로, 있음 있는데로 출력해 준다.

${fn:toLowerCase(string)}
string를 소문자로 변환

${fn:toUpperCase(string)}
string를 대문자로 변환

${fn:trim(string)}    
string의 앞,뒤 공백(whitespace)제거 (중간의 공백은 제거하지 않음)

${fn:escapeXml(string)}
string에 XML과 HTML에서 사용하는 엔티티를 치환한다. 예를들어 '<'는 '&lt;'(맞나?)로 치환한다. 이런것은 스크립트 인젝션 등에 많이 사용 될 수 있다.

${fn:indexOf(string,substring)}
string이 가진 문자열 중 substring가 등장하는 인덱스(int)를 반환

${fn:replace(string, before, after)}
string문자열 중 before의 문자를 after문자로 치환

${fn:substringAfter(string, substring)}
string에서 substring이후부분 반환

${fn:substringBefore(string, substring)}
string에서 substring이전부분 반환

${fn:contains(string,substring)}
  substring를 포함하는지 여부(true, false)

${fn:containsIgnoreCase(string,substring)}
대소문자 구분없이 substring를 포함하는지 여부(true, false)

${fn:endsWith(string, suffix)}
string이 suffix로 끝나는지 여부(true, false)

${fn:startsWith(string, prefix)}
string이 prefix로 시작하는지 여부(true, false)

${fn:join(array, separator)}
array 컬랙션을 구분문자로 합쳐서 반환

${fn:length(item)}
컬랙션 길이(int) 반환

${fn:split(string, separator)}
string를 구분문자로 나누어 배열 반환


------------------------------------------------------------------------
# fmt
JSTL은 <fmt/>에서 이런한 메시지 부분을 지원해 주고 있다. 물론 지역화를 위해 지역에 맞는 시간을 맞춘다던지 하는 기능역시 있지만, 필자는 이부분은 크게 사용하지 않을 것으로 예상되 메시지에 관한 부분만 다루고자 한다.(혹은 차후 수정하여 업데이트 하거나 새로운 포스트로 작성할 예정이다. 어쨋든 지금 알아볼 사항은 <fmt/>의 메시지부분이다.)

JSTL API : http://java.sun.com/products/jsp/jstl/1.1/docs/tlddocs/index.html


먼저 선언은 다음과 같다.
  1. <%@ page language="java" contentType="text/html; charset=UTF-8" 
  2.     pageEncoding="UTF-8"%>  
  3. <%@ taglib prefix="c"   
  4.     uri="http://java.sun.com/jsp/jstl/core" %>  
  5. <%@ taglib prefix="fmt" 
  6.     uri="http://java.sun.com/jsp/jstl/fmt" %>  

기타 설정에 관해선 이전 포스트를 참조하면 될 것이다.

먼저 .properties파일이 있어야 한다. 샘플로 사용하기 위해 간단한 파일을 다음과 같이 작성해 보자.
pupustory.welcome= hello {0} !! your message_{1}
pupustory.msg.sample=한글도 잘되나 보는거에요.
pupustory.msg.user.help=도움이 필요하면 .. 알아서 찾아서 하시라능..
파일명은 msg.properties로 하겠다. properties에 대한 정보는 우측에 있는 검색에 properties로 나오는 포스트를 참조하면 된다.(전에 포스트 해뒀음..!)

이제 어디다 저장할까 ..? 설마 c:\project\...등에 저장할 생각이라면.. 관두길 바란다. 우리는 웹어플을 하고 있으므로 WEB-INF에 있어야 할 것이다. 그리고 위치는...? .properties는 일반 소스처럼 관리하면 된다. 예를들어 패키지 구성이 pupustory. ... ... ... 과 같이 되어있다면 pupsutory.message 이런식으로 패키지를 만들고 하위에 위 내용의 msg.properties를 넣으면 된다.

<fmt:setBundle basename="" scope="" var="" />
먼저 properties를 불러오는 코드는 위와 같다. basename는 경로를 의미하는데 위에 설명한데로 소스와 같이 관리되므로 pupustory.message.msg로 하면 된다.(.properties는 넣지말자!)  var는 지겹게 봐왔지만 사용할 변수다. 이제 var의 이름으로 접근해 메시지를 불러올 것이다.

<fmt:message bundle="" key="" var="" scope=""/>
bundle는 위에 지정한 properties의 변수 명이다. key는 내가 찾고자 하는 메시지를 의미한다.

<fmt:param value="">
properties에 파라미터를 던져 지정된 값을 설정한다. 위 properties에서 {0}부분에 여기에 해당된다. 파라미터값을 던지면 {0}가 바뀌어 반환 될 것이다.
  1. <fmt:setBundle var="msg_prop" basename="pupustory.jstl.msg" />  
  2. <fmt:message bundle="${msg_prop}" key="pupustory.welcome">  
  3.  <fmt:param value="pupustory" />  
  4.  <fmt:param value="my message" />  
  5. </fmt:message><br />  
  6. <fmt:message bundle="${msg_prop}" key="pupustory.msg.sample" /><br />  
  7. <fmt:message bundle="${msg_prop}" key="pupustory.msg.user.help" /><br />  

fmt:parseDate : String 형을 받아서 워하는 포멧으로 자료형을 Date 형태로 변경 시켜 준다.
fmt:formatDate : Date 형을 받아서 원하는 포멧으로 날짜 형태를 변경시켜 준다.

 ex)
<fmt:parseDate value="${applDt}" var="dateFmt" pattern="yyyymmdd"/>
<fmt:formatDate value="${dateFmt}" pattern="yyyy-mm-dd"/>

위에 작성한 코드대로 잘 나올 것 이다.

만약 한글이 깨진다면 ...? 대부분 properties파일이 아니라 그럴 수 있다. 만약 한글로 작성하고 txt파일로 그냥 저장 후 확장자만 바꾸게 되면 당연히 깨지게 된다. JVM은 유니코드로 구성되어 있는데 당연히 유니코드로 된 문자만 제대로 출력되기 때문이다. 이럴경우엔 뭐 ..native2ascii 이전파일 새로운파일 <--로 변경하는 방법이나 .. new Properties().store()...를 이용하는 방법이 있을 수 있다.

앞에서 얘기한데로 국제화에 맞추려고 사용하는것에 메시지라고 했다. 그렇다면 국가가 바뀌게 되면 ..? 이것은 하나의 형식이 존제 하는데 <fmt:setLocale value="" />로 설정하게 된다.

예를들어 한국어와 영어 두개의 언어를 지원한다면 파일을 msg_ko.properties , msg_en.properties로 작성하고 이용하면 된다. 페이지에선 <fmt:setLocale value="ko" />등의 방법으로 미리 설정해 주면 되는데, 영어로 바뀌게되면 value부분만 변경해 주면 된다.

------------------------------------------------------------------------

# xml

xml을 이용하기 위한 JSTL tlb 사용법을 알아보자. 지금까진 별도의 .jar없이(JSTL관련 제외)사용했지만 xml 이용을 위해선 xalan.jar를 추가해야 한다. 만약 추가 하지 않으면 다음과 같은 문제를 발견할 것이다.

root cause

java.lang.NoClassDefFoundError: org/apache/xpath/XPathException

따라서 먼저 xalan.jar를 설치해야 한다.
JSTL xml 사용을 위한 xalan.jar 추가방법
1. xalan.jar 라이브러리를 다운로드 2. 프로젝트에 xalan.jar 추가

추가된 xalan.jar 보기


<x:parse doc="" filter="" scope="" scopeDom="" systemId="" var="" varDom="" xml=""> body </x:parse>
Dom이 분은 부분은 Dom으로 이용하는 의미고 .. var는 파싱된 xml 변수이다. 만약 외부에서 가져오는 부분이 있다면 jstl core부분에서 다룬 <c:import url="" var="xml"/>로 포함시킨 뒤 이것을 파싱해야 한다. <x:parse xml="$xml" />의 식으로 사용하면 된다. 만약 직접 작성되는 xml이라면 body부분에 직접 작성할 수도 있다.(<x:parse var="xmldata"> <root></root></x:parse>)

filter는 org.xml.sax.XMLFilter인스턴스를 지정하여 파싱 전 문서를 걸러낸다. 이부분은 필자도 구체적으로 사용한바 없어 추가설명은 넘어가겠다.
  1. <x:parse var="xmldata">  
  2. <root><user>  
  3.   <name att="히히히">pupustory</name>  
  4.   <age>27</age>  
  5.   <email>pupustory@gmail.com</email>  
  6.   <name att="헤헤헤">yaho</name>  
  7.   <age>26</age>  
  8.   <email>yaho@myemail.com</email>  
  9.   </user>  
  10.   <user>  
  11.   <name att="호호호">hehe</name>  
  12.   <age>16</age>  
  13.   <email>hehe@myemail.com</email>  
  14.   <name att="후후후">hihi</name>  
  15.   <age>17</age>  
  16.   <email>hihi@myemail.com</email>  
  17.  </user>  
  18. </root>  
  19.  </x:parse>  
  20. <x:set select="count($xmldata//*/name)" var="values"/>  


<x:set var="" select="" scope=""/>
위 예제코드에서 사용한데로 select를 통해 저장된 xml정보를 변수에 저장 했다. 여기서 jstl의 xml은 select를 통해 변수를 선택 하는데 count()는 xml부분에서 사용하는 '함수'로 선택된 노드의 갯수를 가져온다.

따라서 위 코드의 name노드는 총 4개이므로 4라는 값이 변수에 저장된다. 노드번호 접근은 배열과 마찬가지로 []로 접근하는데 시작은 1부터 시작한다.(자세한건xml관련 자료 참조) count()와 같은 함수는 여럿 있는데 그중 last()는 마지막 노드를 지정함을 의미한다.

xml에 접근하는데 있어 파싱된 변수 xmldata에 $xmldata/로 접근하는데 /가 한개 더 온 것은 루트노드(xml에서 말하는 root node)를 의미하고, *은 모든 노드를 의미 한다.

일반적으로 노드접근은 상단의 예제처럼 하고, 속성에 대한접근은 @로 이용하는데 위 예제에서 name부분에 att라는 속성이 있다. 만약 att속성 내용을 모두 출력하고자 한다면 다음과 같은 방식을 이용하면 된다.
<x:forEach select="$xmldata//*[name()='name']" var="node">
<x:out select="@att"/>
</x:forEach>
[name()='']부분은 엘리먼트 이름을 의미한다. 위에서 name엘리먼트 이므로 name를 적었다. 출력부분에 "@att"부분은 편리하게도 node값의 속성중(@가 붙었으므로) att인값을 가져온다는 의미이다. 모든 노드의 속성과 차일드 노드의 값도 저런식으로 접근하여 출력할 수 있다.

<x:forEach select="$xmldata//*[name='pupustory']" var="node">
<x:out select="age"/>
<x:out select="email"/>
</x:forEach>

이것은 루트노드에서 모든노드 중 가지고 있는 name노드가 'pupustory'인 값을 가져오는 것 이다. 노드 검색의 경우 [name()='nodename']로 사용하지만 노드가 갖고있는 값은 위와 같은 방식으로 접근 한다. 마찬가지로 속성값을 검색할 경우엔 [@att='']로 사용하면 된다.

name노드가 pupustory인 값은 단 하나이므로 forEach는 한번만 돌고, 노드 age와 email를 출력하는 부분이다.
<x:forEach select="" begin="" end="" step="" var="" varStatus=""></x:forEach>

<x:if select="" var="" scope=""></x:if>

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

<x:choose>


<x:when select=""> body1</x:when>


<x:when select="">body 2</x:when>


<x:otherwise>other body </x:otherwise>


</x:choose>


모두 core부분에서 다룬 내용이므로 별도의 설명은 않하고 스펙만 나열 하였다. 역시 xml에서 가장 큰 문제는 어떻게 노드값을 가져오냐 가 아닐까 싶다. 무엇보다 xml에서 사용한 부분은 출력시 core부분이 아닌 xml부분으로 사용해야 한다는 점이다. 필자는 멍청하게도(..)<c:out/>로 구성했다 계속 null값이 나와 애먹었는데 .. <x:out/>를 이용하라고 해서 해보니 .. 문제 없다 --b



------------------------------------------------------------------------
# sql


  1. <%@ page language="java" contentType="text/html; charset=UTF-8" 
  2.     pageEncoding="UTF-8"%>  
  3. <%@ taglib prefix="c"   
  4.     uri="http://java.sun.com/jsp/jstl/core" %>  
  5. <%@ taglib prefix="sql" 
  6.     uri="http://java.sun.com/jsp/jstl/sql"%>  
  7. <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"   
  8.     "http://www.w3.org/TR/html4/loose.dtd">  
  9. <html>  
  10. <head>  
  11. <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">  
  12. <title>JSTL</title>  
  13. </head>  
  14. <body>  
  15. <sql:setDataSource  
  16.  var="db" 
  17.  driver="oracle.jdbc.driver.OracleDriver" 
  18.  url="jdbc:oracle:thin:@127.0.0.1:1521:xe" 
  19.  user="pupustory" 
  20.  password="stares" 
  21. />  

<sql:setDataSource
 driver    ="expression"
 password  ="expression"
 user      ="expression"
 url       ="expression"
 var       ="expression"
 scope     ="expression"
 dataSource="expression"
/>
JSTL의 sql은 말 그대로 sql을 사용하기 위해 지원하는 테그 라이브러리 이다. 먼저 db를 사용하기 위해선 커넥션이 필요한데 .. 여기선 데이타소스를 통해 db에 접근 한다. 속성부분들이 워낙 많이 알려진 부분이니 넘어가고 .. 데이타소스를 사용하는(scope영역에서)부분은 var로 지정한다. 역시 el을 통해 지정된 var에 접근해 쿼리를 수행 한다.

<sql:query
dataSource=""
var=""
startRow=""
maxRows=""
scope=""
sql=""
/>
기본적인 sql쿼리를 수행하는 부분이다. 이것은 update나 insert부분이 아닌 단순 질의에 대한 부분이다. dateSource는 상단에서 지정한 데이타소스 변수를 적어주고, var엔 수행 후 레코드를 map으로 받게 된다. sql은 쿼리 수행 구문인데 여기에 적거나 아니면 <sql:query> write query </sql> 형식으로 사용 가능하다.

  1. <sql:query var="record" dataSource="${db}">  
  2.  select * from dual  
  3. </sql:query>  
  4.  
  5. <c:set var="values" value="${record.rows[0]}"/>  
  6. <c:out value="${values}" />  


map배열이므로 [0]통해 첫번째에 접근했고, 사용자가 경우에 따라 forEach를 통한 리스트 출력도 가능하다. map형식이므로 접근하는 key는 컬럼명이 된다.

<sql:update dataSource=""
 scope=""
 sql=""
 var=""/>
iBATIS에선 update, insert가 구분되어 있고, 통합적으로 사용하는 statment가 있지만 jstl sql에선 조회를 제외한 모든것은 update에서 처리 된다. 물론 테이블 생성역시 update를 이용 한다.

<sql:transaction
 dataSource=""
 isolation=""
/>
sql수행이므로 당연히 트랜잭션을 지원 한다. 속성도 생각보다 간단하다. isolation는 트랜잭션의 레벨을 의미하는데 .. 구채적으로 사용해보지 않았다. --; (다른 블로그나 정보를 참조하세요 !) dataSource부분은 위와 같은 형식이지만, 트랜잭션에 사용되는 update같은 부분에 별도의 dataSource를 작성하지 않는다. 만약 작성한다면 Illigal을 만나게 된다.

이제 직접 위의 소스를 모두 한번에 확인할 수 있는 소스를 만들어 보겠다.
  1. <sql:setDataSource  
  2.  var="db" 
  3.  driver="oracle.jdbc.driver.OracleDriver" 
  4.  url="jdbc:oracle:thin:@127.0.0.1:1521:xe" 
  5.  user="pupustory" 
  6.  password="stares" 
  7. />  
  8.  
  9. <!-- 생성,삽입,수정은 모두 sql:update를 사용 함 -->  
  10. <!-- 테이블 생성 -->  
  11.  
  12. <sql:update  dataSource="${db}">  
  13.  create table jstl_test ( 
  14.  id varchar(12),name varchar(20))  
  15. </sql:update>  
  16.  
  17. <!-- 생성 테이블에 데이타 삽입(인자 없음) -->  
  18. <sql:update dataSource="${db}">  
  19.  insert into jstl_test values('1','pupustory')  
  20. </sql:update>  
  21.  
  22. <!-- 생성 테이블에 데이타 삽입(인자 있음) -->  
  23. <sql:update dataSource="${db}">  
  24.  insert into jstl_test values(?,?)  
  25.  <sql:param value="2" />  
  26.   <sql:param value="pupustory" />  
  27. </sql:update>  
  28. <!-- 삽입 데이터 조회 -->  
  29. <sql:query var="record" dataSource="${db}">  
  30.  select * from jstl_test  
  31. </sql:query>  
  32.  
  33. <c:forEach var="value" items="${record.rows}">  
  34.  <c:out value="${value.id}" />  
  35.  <c:out value="${value.name}" />  
  36.  <br />  
  37. </c:forEach>  
  38. <!-- 트랜잭션 샘플 시작 -->  
  39. <sql:transaction dataSource="${db}">  
  40.  <sql:update >  
  41.  insert into jstl_test values('3','pupustory')  
  42. </sql:update>  
  43.  
  44. <sql:update >  
  45.  insert into jstl_test values('4','pupustory')  
  46. </sql:update>  
  47. <!-- 여기서 문제가 발생해 위 데이터 삽입 안됨 -->  
  48.  <sql:update >  
  49.  update jstl_test set  
  50.   name='컬럼크기이상의데이터삽입시도121111122222222222222' where id='4' 
  51. </sql:update>  
  52. </sql:transaction>  
  53. <!-- 트랜잭션 샘플 끝 -->  

테이블 생성 -> 로우 삽입 -> 등록 로우 정보 확인 -> 트랜잭션 이용 -> 문제가 발생해 추가삽입부분 무시되고 Exception발생 의 프로세스이다.

사실 sql은 잘 사용할지 의문이다. 물론 외부의 dataSource를 받아와 사용할 수 있다지만 .. 이건 고전적인 방식이므로, 요즘 지겹도록 듣는 MVC에는 맞지 않는듯 하다.

논 외의 얘기지만 .. sql을 보면서 느낀 것 인데 .. (사실 이와 관련 없지만) 초보중의 초보인 필자 생각으론 .. 이것도 어떨때 쓸만할 지도 모른다는 생각을 한다. 예를들어 한 화면에 5만개의 레코드를 출력한다면 .. dao에서 5만개의 bean을 작성해야 할 것이다. 차라리 이런거라면, db에서 가져옴과 동시에 출력하는 방식 어떨까도 싶다.


※ 위 내용은, 여러 자료를 참고하거나 제가 주관적으로 정리한 것입니다.
   잘못된 정보나 보완이 필요한 부분을, 댓글 또는 메일로 보내주시면 많은 도움이 되겠습니다.
11 19, 2009 17:26 11 19, 2009 17:26


Trackback URL : http://develop.sunshiny.co.kr/trackback/339

Leave a comment


Recent Posts

  1. HDFS - Python Encoding 오류 처리
  2. HP - Vertica ROS Container 관련 오류...
  3. HDFS - Hive 실행시 System Time 오류
  4. HP - Vertica 사용자 쿼리 이력 테이블...
  5. Client에서 HDFS 환경의 데이터 처리시...

Recent Comments

  1. 안녕하세요^^ 배그핵
  2. 안녕하세요^^ 도움이 되셨다니, 저... sunshiny
  3. 정말 큰 도움이 되었습니다.. 감사합... 사랑은
  4. 네, 안녕하세요. 댓글 남겨 주셔서... sunshiny
  5. 감사합니다 많은 도움 되었습니다!ㅎㅎ 프리시퀸스

Recent Trackbacks

  1. Mysql - mysql 설치후 Character set... 멀고 가까움이 다르기 때문 %M

Calendar

«   10 2019   »
    1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31    

Bookmarks

  1. 위키피디아
  2. MysqlKorea
  3. 오라클 클럽
  4. API - Java
  5. Apache Hadoop API
  6. Apache Software Foundation
  7. HDFS 생태계 솔루션
  8. DNSBL - Spam Database Lookup
  9. Ready System
  10. Solaris Freeware
  11. Linux-Site
  12. 윈디하나의 솔라나라

Site Stats

TOTAL 2724069 HIT
TODAY 535 HIT
YESTERDAY 589 HIT