Velocity란 무엇인가?
Velocity는 자바 기반의 템플릿 엔진이다.
Velocity는 웹 페이지 디자이너들이 자바 코드안에서 정의된 메소들에 접근하는 것을 도와준다. 이것은 웹 페이지 디자이너들이 자바 개발자들과 함께 Model-View-Controller(MVC) 아키텍쳐에 따른 웹 사이트를 각자의 영역에서 최선의 결과를 가져오도록 도와준다는 것을 의미한다.
Velocity는 웹 페이지로부터 자바 코드를 분리할 수 있고, 웹사이트를 계속 오랫동안 유지할 수 있으며, 자바 서버 페이지(JSP)의 실용적인 대안을 제공한다.
Velocity로 무엇을 할 수 있나?
당신이 진흙(Mud)을 판매하는 "온라인 진흙 가게"의 페이지 디자이너 이라고 가정해보자. 그리고 고객들은 다양한 종류와 많은 수량의 진흙을 주문하여 당신의 가게는 날로 번성하고 있다.
고객들은 사용자 이름과 패스워드를 입력하고 당신의 사이트에 로그인하여 자신이 이전에 주문했던 주문목록을 조회하고, 또 다른 진흙을 살 수도 있다. 모든 고객에 관한 정보는 당신의 데이타 베이스안에 저장되고 있다.
데이타 베이스에 따르면 특별히 설악산에서 만든 진흙이 매우 인기가 좋으며, '설악산 진흙'보다 인기가 덜 한 일본산 빨간 진흙도 정기적으로 일본에서 수입하고 있다.
그러던 어느날 당신은 왜 '설악산 진흙'에 흥미를 느끼는 수많은 고객들과의 특별한 거래를 찾는데 Velocity를 사용하지 않는 지에 대한 의문을 갖게된다.
Velocity는 웹페이지를 통한 당신의 온라인 방문객들에게 진흙 판매를 쉽게 해준다. 진흙 가게의 웹사이트 디자이너인 당신은 고객이 웹 사이트 로그인 후에 보게 될 특별한 웹 페이지를 원하고 있다.
명심하라. 당신은 개발자들이 데이터베이스에서 필요한 정보를 어떻게 추출하는지에 대해 걱정할 필요가 없다. 당신은 단지 그것이 올바르게 작동한다는 것만 기억하면 된다. 그렇게 되면 당신은 당신만의 페이지 디자인을 하게 되고, 개발자들은 그들만의 일을 하게 된다.
이런 결과로, 당신은 로그인한 사용자에게 나타낼 동적인 정보를 아래와 같이 velocity Template Language(VTL) 문장을 사용해 웹페이지에 넣을 수 있게 된다.
Hello, $customer.Name! <br>
$flogger.getPromotion( $mud )
$customer는 현재 로그인한 사용자에 대한 정보를 가지고 있고, $promotion은 로그인한 고객별로 데이타 베이스를 조회에 해당 고객에 맞는 추천 상품을 소개하는 일을 한다.
그래서 '설악산 진흙'을 오랫동안 구입해온 기록을 가진 고객이 로그인 했을 때 '설악산 진흙 현재 대폭 세일중!!' 이라는 메시지를 정면에서 보게 될 것이다.
Velocity의 힘과 유연함은 이렇게 VTL 레퍼런스와 함께 당신에게 제공된다.
VTL (Velocity Template Language)
VTL은 Velocity에서 템플릿 개발에 사용되는 언어로 레퍼런스(Reference), 디렉티브(Directive), 그리고 주석(Comment)으로 구성된다.
레퍼런스 |
${variable} |
컨텍스트에서 제공되는 변수에 대한 레퍼런스 |
${variable.property} |
속성에 대한 레퍼런스 |
|
${variable.method(args)} |
메소드 대한 레퍼런스 |
|
디렉티브 |
#set |
레퍼런스의 값을 설정 |
#if #elseif #else |
조건문 제어 |
|
#foreach |
반복문 제어 |
|
#include |
파싱되지 않는 로컬 파일 출력 |
|
#parse |
파싱되는 로컬 템플릿 출력 |
|
#stop |
템플릿 엔진의 동작 정지 |
|
#macro |
반복적으로 사용될 매크로 정의 |
|
주석 |
## |
한 줄짜리 주석 |
#* .... *# |
여러 줄에 걸친 주석 |
VTL은 위 표에서 정리한 것처럼 너무나 단순하기 때문에 흔히 성냥갑 표지에 다 적을 수 있을 만큼 작은 API라고 불려진다.
이는 뷰 작업을 개발자와 디자이너가 함께 진행해 나간다는 점을 감안하면 매우 바람직한 일이라고 볼 수 있다.
VTL을 통해 작성된 벨로시티 템플릿(vm 파일)은 다음과 같은 패턴을 통해 처리 된다.
|
템플릿 엔진이 동작하는 방식을 정리해 보면, 개발자는 사용자에게 보여 질 디자인을 위해 VTL을 이용한 템플릿 파일을 작성하고, 그 처리를 위한 코드를 개발한다.
자바 코드와 템플릿 간의 필요한 정보 전달은 컨텍스트 객체를 통해 이루어진다.
이러한 2개의 파일을 입력받아 벨로시티는 템플릿을 토대로 렌더링한 결과 페이지를 출력하게 되는 것이다.
템플릿에 어떤 내용이 담겨 있느냐에 따라 결과 페이지는 일반 텍스트가 될 수도 있고, HTML이나 SQL, PostScript, XML 등도 될 수 있다.
Velocticy 템플릿 언어 (VTL)
Velocticy 템플릿 언어(velocity Template Language : VTL)는 웹 페이지에서 동적인 내용을 구체화하기 가장 쉽고, 가장 간결하고 가장 확실한 방법을 제공하는 수단이다.
심지어 프로그래밍 해본 경험이 적거나 전혀 없는 페이지 개발자도 웹사이트에서 동적인 내용를 구체화 하는데 VTL을 금방 사용할 수 있다.
VTL은 웹사이트에서 동적인 내용을 끼워넣는데 필요한 레퍼런스를 사용한다. 레퍼런스의 타입은 variable이다.
Variables는 자바 코드에서 정의된 것에 대해 언급할 수 있는 레퍼런스의 한 타입 이거나, 또는 웹페이지 자체의 VTL 에서 지원하는 타입일 수 있다.
아래는 HTML 문서안에 삽입될 수 있는 VTL문의 예제다.
#set ( $a = "velocity" )
이 VTL문은 모든 VTL문처럼 #기호로 시작하고 set 명령어를 포함하고 있다. 온라인 고객이 당신의 웹 페이지를 요청할 때, Velocticy 템플릿 엔진은 당신의 웹 페이지에 명시된 모든 #기호를 검색한다. VTL을 시작할 #기호와 VTL에서 아무일도 않는 #기호들을 분리한다.
위 예제에 표시된 set 명령어는 둥근괄호 안에서 사용하며 특정 변수에 값를 부여하는 일을 한다. 변수는 좌변에, 변수의 값는 우변에 나열되며 좌변과 우변은 = 기호로 구분되어 진다.
위의 예에서, 변수는 '$a'이고 이 변수에 할당된 값은 'Velocity'이다. 이 변수는 다른 모든 레퍼런스들처럼 $기호로 시작한다. 값은 항상 인용부호 사이에 존재한다.
Velocticy는 문자열(String) 타입만 변수에 할당할 수 있기 때문에 다른 데이타 타입들과의 혼란은 없다.
정리해보면 아래와 같다.
레퍼런스는 $로 시작하고 어떤 것을 얻는데 사용된다.
명령어는 #로 시작하고 어떤 동작을 수행하는데 사용된다.
위 예제에서 #set은 변수에게 값을 할당하는데 사용되고 $a 변수는 템플릿에서 "velocity"를 출력하는데 사용되었다.
안녕 velocity
변수에 값을 할당했으면, 당신의 HTML 문서내 어디서나 변수를 레퍼런스할 수 있다. 다음의 예에서 $foo에 값이 할당되고 그 후 레퍼런스 되는 모습을 볼 수 있다.
#set ($ foo = "velocity" )
Hello #foo World!
위 문장은 결국 웹페이지에 "Hello Velocity World!"를 출력할 것이다.
VTL 명령어들을 포함한 문장들을 좀더 읽기 쉽게 만들기 위해, 굳이 그럴 필요는 없지만 가급적 VTL문장을 새로운 줄에서 시작하도록 권장한다.
set 명령어는 나중에 매우 세부적으로 다시 살펴보게 될 것이다.
주석 처리
주석은 velocity 템플릿 엔진에 의해 해석되지 않는 설명문이다. 주석은 당신의 오래된 기억을 상기시키거나, 당신의 VTL문이 무엇을 하고 있는지, 또는 당신이 찾는 다른 다른 목적들을 설명하기에 유용한 방법이다.
아래에 VTL의 주석의 예가 있다.
##This is a single line Comment.
한줄 주석문은 ##로 시작하고 라인의 끝에서 끝난다. 당신이 여러 줄의 주석을 사용한다면, 다수의 한줄 주석을 여러 줄에 쓸 필요는 없다.
문장이 #*로 시작하고 *#로 끝나는 Multi-line 주석이 이런 상황에 매우 유용하다.
#*
Thus begins a multi-line comment. Online visitors won't
see this text because the velocity Templating Engine will
ignore it.
*#
아래 나오는 세 번째 타입의 주석은 문서의 저자와 버전정보와 같은 메타정보를 저장하는데 사용될 수 있다.
#**
This is a VTL comment block and
may be used to store such information
as the document author and versioning
information:
@author
@version 5
*#
참조 (References)
VTL 에서 지원하는 세가지 타입의 레퍼런스가 있다.
변수
속성
메소드
개발자들은 디자이너가 VTL을 이용하는 템플릿에서 개발자가 설정한 레퍼런스를 정확히 사용하기 위해 레퍼런스의 특별한 이름을 지어주어야 한다.
레퍼런스로 오고 가는 모든 것은 문자열(String) 객체로 처리된다. 만약 $foo(Integer 타입이라 가정한다)를 표현하는 객체가 있다면 Velocity는 문자열 객체를 얻기위한 매소드로 .toString()을 요청 할 것이다.
변수 (Variables)
변수의 표기법은 VTL 식별자로부터 불려온 '$'기호로 시작된다. VTL 식별자는 알파벳 (a...z, or A...Z)으로 시작해야 하며 나머지는 아래의 문자들로 제한된다.
alphabetic (a .. z, A .. Z)
numeric (0 .. 9)
hyphen ("-")
underscore ("_")
여기 VTL안에서 유효한 변수 레퍼런스의 예가 몇 개 나온다.
$foo
$mudSlinger
$mud-slinger
$mud_slinger
$mudSlinger1
VTL 변수가 $foo로써 레퍼런스 될 때, 변수는 템플릿안의 set 명령어나 자바 코드로부터 값을 얻을 수 있다.
예를 들어 자바 변수 $foo가 "value bar"라는 값을 가지고 있다면, "value bar"는 웹페이지내에 정의된 모든 $foo를 대체 하게 된다.
만약 다음 문장이 웹페이지 내에 정의된다면....
#set ( $foo = "bar" )
결과는 이 명령어 하위에 나오는 모든 $foo를 "bar"로 대체할 것이다.
속성 (properties)
VTL 레퍼런스의 두번째 특징은 속성이다.
속성은 특유의 포맷을 가진다. 표기법은 점 기호(".")와 다른 VTL 식별자가 뒤에 따르는 '$' 기호로 구성된다. 아래는 VTL안의 유효한 속성 레퍼런스의 예이다.
$customer.Address
$purchase.Total
위 예제에서 $customer.Address는 두가지 의미을 가질 수 있다.
customer 객체의 멤버 변수 Address를 레퍼런스 한다.
customer 객체의 메소드 getAddress()를 레퍼런스 한다.
즉, $customer.getAddress()는 $customer.Address로 생략해서 사용할 수 있다. 웹 페이지가 요청될 때, Velocity는 이들 두 가능성을 이치에 맞는지 분별하여 적당한 값은 반환하게 된다.
메소드 (Method)
메소드는 자바코드 안에서 정의되며, 계산을 하거나 어떤 값을 얻는 것과 같이 유용한 무언가를 수행한다. 아래는 유효한 메소드 레퍼런스의 예이다.
$customer.getAddress()
$purchase.getTotal()
$page.setTitle( "My Home page" )
$person.setAttributes( ["Strange", "Weird", "Excited"] )
예제에서 나온 $customer.getAddress()와 $purchase.getTotal()은 앞선 예제에서 나온 $customer.Address과 $purchase.Total 레퍼런스의 결과와 정확히 일치한다.
그러나 $page.setTitle( "My Home page" )과 같이 메소드에서는 인자를 넘길 수 있다는 점이 속성과 다르다. 참고로 $person.setAttributes( "Strange", "Weird", "Excited"? )는 인자로 문자열 배열을 넘기고 있다.
형식적인 레퍼런스 표기법 (Formal Reference Notation)
앞서 나온 것은 레퍼런스에 대한 속기 표기법이었다. 이제 형식적 표기법에 대해 살펴보자.
${mudSlinger}
${customer.Address}
${purchase.getTotal()}
거의 모든 경우에 당신은 레퍼런스를 위하여 앞서 나온 속기 표기법을 사용할 것이지만, 어떤 경우에는 형식적 표기법이 정확한 프로세스를 위하여 필요할 수도 있다.
만약 당신이 $vice라는 변수를 사용하는데 이 변수 바로 뒤에 "fly"라는 문장이 뒤따른다고 생각해보자. 속기 표기법을 사용할 경우의 다음 예제를 살펴보면....
Jack is a $vicefly
예제에 나온 $vicefly라는 변수는 우리가 희망한 변수가 아니다. 이 결과로 Velocity는 $vice가 아닌 $vicefly를 변수로 가정해서 처리하게 된다. 결국 화면에는 우리가 예상하지 못한 $vicefly가 그대로 표시될 것이다.
아래 형식적 표기법을 통해 이 문제를 해결할 수 있다.
Jack is a ${vice}fly
이제 Velocity는 $vicefly가 아닌 $vice가 변수라는 것을 알게 된다. 기억하자. 형식적 표기법은 레퍼런스들이 템플릿 안에서 텍스트에 직접 붙어 있을 때 유용하게 사용된다.
숨겨진 레퍼런스 표기법 (Quiet Reference Notation)
Velocity는 사전에 정의되지 않은 변수를 만나게 되면, 변수값을 그대로 화면에 출력하게 된다.
다음의 예제를 살펴보자.
<input type="text" name="email" value="$email" />
위에 나온 $email이 사전에 정의되지 않았을 경우 화면에 나오는 텍스트필드의 초기값에는 $email이라는 값이 그대로 표시될 것이다. 이것은 우리가 원하는 결과가 아니다.
이제 다음처럼 예제를 바꿔보자.
<input type="text" name="email" value="$!email"/>
이제 화면에는 텍스트필드의 값이 빈 공백이 출력될 것이다. 형식적 표기법을 사용한 다음 예제도 같은 결과를 가져온다.
<input type="text" name="email" value="$!{email}"/>
값이 설정되지 않은 변수를 화면에 출력하지 않을 경우 숨겨진 레퍼런스 표기법은 아주 유용하다.
Dollar($)표시의 경우는 어떻게 하는가?
만약 당신이 웹 페이지 내에서 "나는 농부의 가게에서 $2.50를 주고 4파운드의 감자를 샀습니다.!" 라는 문자열을 표시해야 한다고 가정하자.
VTL에서는 앞서 보았듯이 $와 # 같은 특별한 캐릭터들을 사용하고 있어서 언뜻 보면 위 문자열이 제대로 표시가 안될 수도 있을 것 같다.
그러나 VTL 식별자는 항상 대문자나 소문자의 영문자로 시작하기 때문에 위 문장은 아무런 문제가 없다.
escape 캐릭터의 사용
만약 당신이 화면에 $email을 출력해야 한다고 가정하자. 그러나 이미 $email은 값이 설정된 상태라고 하자. 그러면 화면에는 당신이 원하지 않는 $email에 대한 설정값이 화면에 표시될 것이다.
아래 예제가 있다.
#set ( $email = "foo" )
$email
이 경우 화면에는 foo라는 문자열이 출력되어 당신이 원하는 $email이라는 문자는 출력할 수 없게 된다.
이경우 다음과 같이 escape 캐릭터를 사용하면 된다.
#set( $email = "foo" )
$email
\$email
\\$email
\\\$email
결과는 아래와 같이 나올 것이다.
foo
$email
\foo
\$email
만약 $email이 사전에 정의되지 않았다고 가정해보면 어떻게 될까? 결과는 아래와 같을 것이다.
$email
\$email
\\$email
\\\$email
Velocity 문법(지시어)
앞서 배운 레퍼런스(변수)는 웹 디자이너들이 웹 페이지에 동적인 내용을 생성할 수 있도록 도와준다.
반면에 이번에 살펴볼 디렉티브(명령어)는 웹 디자이너들이 실제적으로 웹사이트의 뷰와 컨텐츠를 관리하도록 도와준다.
#set
명령어 #set은 레퍼런스의 값을 설정할 때 사용된다. 값은 변수 레퍼런스나 속성 레퍼런스 둘 모두에 할당될 수 있고, 이것은 아래에 보이는 것처럼 괄호 안에서 명명된다.
#set( $primate = "monkey" )
#set( $customer.Behavior = $primate )
괄호안의 좌측에 위치하는 변수(이하 LHS로 표기, 우측 변수는 RHS로 표기)는 아래에 나오는 레퍼런스 또는 속성 타입이어야 한다.
Variable reference
String literal
Property reference
Method reference
Number literal
ArrayList
아래는 위의 각 타입들에 예제이다.
#set( $monkey = $bill ) ## variable reference
#set( $monkey.Friend = "monica" ) ## string literal
#set( $monkey.Blame = $whitehouse.Leak ) ## property reference
#set( $monkey.Plan = $spindoctor.weave($web) ) ## method reference
#set( $monkey.Number = 123 ) ## number literal
#set( $monkey.Say = ["Not", $my, "fault"] ) ## ArrayList
마지막 줄에서 대괄호로 표시된 element는 ArrayList class의 요소를 정의한다. 그래서 예를 들면, 당신은 $monkey.Say.get(0)을 이용해서 첫번째 배열요소(여기서는 "Not")에 접근할 수 있다.
또한 간단한 수학적 표현도 가능하다.
#set( $value = $foo + 1 )
#set( $value = $bar - 1 )
#set( $value = $foo * $bar )
#set( $value = $foo / $bar )
null 체크
만약 RHS가 속성 또는 그 값이 null인 메소드 레퍼런스 라면, LHS로 할당되지 않을 것이다. 문맥에서 현재의 레퍼런스를 이 매커니즘으로 제거하는 것은 불가능하다. 이런 점은 Velocity의 초보자들이 흔히 혼동 하는 실수다.
예를 들면....
#set( $result = $query.criteria("name") )
The result of the first query is $result
#set( $result = $query.criteria("address") )
The result of the second query is $result
위에서 만약 $query.criteria("name")이 문자열 "bill"로 return되고, $query.criteria("address")이 null로 return되면, 위 VTL의 결과는 아래와 같이 출력될 것이다.
The result of the first query is bill
The result of the second query is bill
이것은 property 또는 매소드 레퍼런스를 거쳐 #set 레퍼런스를 시도한 후,
1. foreach 반복문을 만드는 초보자들을 혼동케하는 경향이 있다.
이때는 아래와 같이 null이 의심가는 레퍼런스를 #if 명령어를 가지고 시험한다.
#set( $criteria = ["name", "address"] )
#foreach( $criterion in $criteria )
#set( $result = $query.criteria($criterion) )
#if( $result )
Query was successful
#end
#end
위의 예에서, query가 성공하였는지 결정하는데 있어 $result의 결과값에 의존하는 것은 현명한 결정이 아니다. $result가 위에서 처럼 조건절 이전에 #set을 통해 설정 되어진 후에는 $result를 null로 다시 되돌릴 수 없다. (#if와 #foreach 명령어의 세부사항들이 이 문서의 뒤에 다루어질 것이다.)
이에대한 하나의 해결책은 $reult를 false로 사전에 설정하는 방법이다. 그런 다음 $query.criteria( ) 호출이 실패하면, 당신은 $result가 null임을 체크할 수 있게 된다.
#set( $criteria = ["name", "address"] )
#foreach( $criterion in $criteria )
#set( $result = false )
#set( $result = $query.criteria($criterion) )
#if( $result )
Query was successful
#end
#end
몇몇의 다른 Velocity 명령어들과 다르게, #set 디렉티브는 #end 문을 가지지 않는다는 점도 참고하라.
문자열 (String literals)
명령어 #set을 사용할 때 큰 따옴표로 지정된 문자열은 아래 예제처럼 파싱되어 출력된다.
#set( $directoryRoot = "www" )
#set( $templateName = "index.vm" )
#set( $template = "$directoryRoot/$templateName" )
$template
당연하겠지만, 결과는 아래와 같다.
www/index.vm
그러나 문자열이 작은 따옴표일 때는 파싱되지 않는다.
#set( $foo = "bar" )
$foo
#set( $blargh = '$foo' )
$blargh
결과는 아래와 같다.
bar
$foo
Velocity에서 파싱되지 않은 텍스트를 출력하기 위해 위에서 처럼 작은 따옴표를 사용할 수 있다.
이 설정은
velocity.properties 설정파일에서 stringliterals.interpolate=false를 설정함에 따라 기본설정을 바꿀 수도 있다.
조건절 (If / ElseIf / Else)
Velocity에서 #if 명령어는 문장이 참인 조건에서 웹페이지가 생성될 때 포함될 문자열을 지정할 수 있다.
#if( $foo )
Velocity!
#end
위에서 #if 명령어는 변수 $foo가 참인지 결정하기 위해 사용되며 아래 2가지 상황일 수 있다.
$foo는 참인 값을 갖는 boolean(true/false)이다.
$foo는 null이 아니다.
Velocity 문맥은 항상 객체(Object)로써 유지된다는 것을 기억하라. 그래서 우리가 boolean이라고 말할 때, 그것은 Boolean(class)으로 표현될 것이다.
예제에서 #if 와 #end 사이에 들어있는 content가 참이면 결과가 나올 것이다. 여기서는 $foo가 참이면, "Velocity!"가 출력될 것이고, 반대로, $foo가 null값이거나 false이면 아무런 내용도 표시되지 않을 것이다.
명령어 #elseif 또는 #else는 #if 요소와 함께 사용될 수 있다. 다음의 예제에서, $foo가 15의 값를 갖고 $bar가 6의 값을 갖는다고 가정해보자.
#if( $foo > 10 )
Go North
#elseif( $foo == 10 )
Go East
#elseif( $bar == 6 )
Go South
#else
Go West
#end
위 예제에서 $foo가 10보다 크면 첫번째 두 비교들이 실패하게 된다. 다음 $bar가 6과 비교되어 참이 되고, 그래서 결과는 "Go South"가 된다.
※ 참고 : '=='로 비교되는 변수는 같은 Object 타입이어야 한다. 그렇지 않으면 결과는 항상 false가 될 것이다.
논리 연산
Velocity는 논리 연산자 AND, OR, NOT 을 지원한다. 아래 예제가 나온다.
## logical AND
#if( $foo && $bar )
This AND that
#end
위에서 #if() 명령은 단지 $foo와 $bar가 참인지만 평가할 것이다. 만약 $foo 가 false라면, 결과는 false가 되며 $bar는 평가되지 않을 것이다. 만약 $foo가 참이라면, Velocity는 $bar의 값을 체크하게 된다. 만약 $bar도 참이면, 결과는 true가 되고 화면에는 "This And that"이 나타날 것이다. $bar가 false라면, 그때 결과는 false이므로 결과는 없을 것입니다.
논리 연산자 OR도 같은 방법으로 작동한다. 아래 예제가 나온다.
## logical OR
#if( $foo || $bar )
This OR that
#end
OR 연산에 대해 별도의 설명은 하지 않는다. 아래는 부정연산의 예제다.
##logical NOT
#if( !$foo )
NOT that
#end
여기서, $foo가 참이라면, 그 때 !$foo는 false로 평가하고, 아무런 출력이 없게된다. 만약에 $foo가 false라면, 그 때 !$foo는 참으로 평가되어 화면에서 "NOT that"이 출력될 것이다.
※ 주의 : 이것을 완전하게 앞서 배운 숨긴(quiet) 레퍼런스와 혼동하지 않도록 조심하라. 숨긴 레퍼런스의 형식은 $!foo 이다.
반복문 (Loops)
명령어 #foreach는 반복문을 사용할 때 필요하다.
<ul>
#foreach( $product in $allProducts )
<li>$product</li>
#end
</ul>
위 예제에서 #foreach loop는 $allProducts 컬렉션(object) List 안의 전체 product에 대해 반복문을 수행하도록 한다. 위 loop를 통해서 $allProducts 내에 담긴 Object는 $product 변수로써 레퍼런스하게 된다.
위에 나온 $allProducts 변수에 사용되는 타입은 아래와 같다.
Vector
Hashtable
Array
이제 $allProduct가 Hashtable이라고 가정하자.
만약 당신이
Hashtable에 담긴 키값을 검색해야 한다면, 아래와 같은 코드를 사용하면 된다.
<ul>
#foreach( $key in $allProducts.keySet() )
<li>Key : $key -> value : $allProducts.get($key)</li>
#end
</ul>
또한 Velocity는 당신이 반복문의 횟수(loop counter)를 얻을 수 있는 간단한 방법을 제공한다.
<table>
#foreach( $customer in $customerList )
<tr><td>$velocityCount</td><td>$customer.Name</td></tr>
#end
</table>
velocity.properties 파일에 명시되어있는, loop counter 변수 레퍼런스를 위한 기본값은 $velocityCount이다. 기본값에 따라 카운터가 1에서 시작하지만, 이것은 velocity.properties 파일안에서 0 이나 1 둘 모두로 설정할 수 있다. 아래는 velocity.properties 파일에 지정된 관련 설정 내용이다.
# Default name of the loop counter
# variable reference.
directive.foreach.counter.name = velocityCount
# Default starting value of the loop
# counter variable reference.
directive.foreach.counter.initial.value = 1
인클루드 (Include)
명령어 #include는 템플릿에 local 파일을 끼워넣을 수 있도록 해준다. local file은 #include 명령이 정의된 위치에 정확히 삽입된다.
아래는 #include시 참고할 사항이다.
파일의 내용은 템플릿 엔진을 통해 파싱되지 않는다.
안전상의 이유로, 파일은 오직 TEMPLATE ROOT 아래에만 위치해야 한다.
#include( "one.txt" )
위에서 처럼 #include 명령이 요청한 파일은 큰 따옴표로 지정된다. 만약 하나 이상의 파일이 포함된다면, 콤마(,)로 구분되어야 한다.
#include( "one.gif", "two.txt", "three.htm" )
포함되는 파일은 파일 이름 대신에 변수를 사용할 수도 있다. 아래 파일이름과 변수 모두를 지정하는 에제가 나온다.
#include( "greetings.txt", $seasonalstock )
파싱 (Parse)
명령어 #parse는 템플릿 디자이너가 VTL이 지정되어 있는 동적인 템플릿을 포함하는 local file을 끼워넣도록 해준다. Velocity는 이 파일에 명명된 VTL을 분석하고 평가된 결과를 #parse 명령이 정의된 위치에 정확히 삽입한다.
아래는 #parse시 참고할 사항이다.
파일의 내용은 템플릿 엔진을 통해 파싱된다.
안전상의 이유로, 파일은 오직 TEMPLATE ROOT 아래에만 위치해야 한다.
#parse( "me.vm" )
앞서 나온 #include 명령처럼, #parse 역시 변수를 취할 수 있다. 주의해야 할 것은 #include 명령과 다르게, #parse는 단지 하나의 파일만을 취할 수 있다는 점이다.
Velocity는 또한 #parse 문장을 포함하고 있는 템플릿을 #parse 인자로 가질 수 있다.
파싱되는 파일의 제한을 위한 최적의 기본값은 10이며 velocity.properties 파일내에 directive.maxdepth=10 이라는 설정을 통해 이를 제어할 수 있다.
아래 예제를 보자.
1) default.vm
Count down.
#set( $count = 8 )
#parse( "parsefoo.vm" )
All done with dofoo.vm!
2) parsefoo.vm
#set( $count = $count - 1 )
#if( $count > 0 )
#parse( "parsefoo.vm" )
#else
All done with parsefoo.vm!
#end
위 예제에 따라 default.vm에서 $count는 8부터 count down하면서 parsefoo.vm을 파싱하게 된다.
그리고 count가 0에 도달할 때, Velocity는 "All done with parsefoo.vm!" 이라는 메세지를 표시하고, 이 시점에서, 제어권은 default.vm으로 돌아가 "All done with dofoo.vm!" 이라는 메시지를 출력할 것이다.
중지 (Stop)
명령어 #stop은 템플릿 엔진의 실행과 return을 강제로 멈추도록 하는데 사용한다.
보통 디버깅(debugging)
목적으로 사용된다.
#stop
다음으로 Velocity의 나머지 특징과 기타 살펴볼 내용들에 대해 설명을 계속한다.
수학적인 기능 (Math)
Velocity #set 명령어를 가지고 템플릿들에서 사용될 수 있는 수학적인 기능들을 제공한다. 다음의 식들은 각각 덧셈, 뺄셈, 곱샘 그리고 나눗셈에 대한 예제이다.
#set( $foo = $bar + 3 )
#set( $foo = $bar - 4 )
#set( $foo = $bar * 6 )
#set( $foo = $bar / 2 )
#set( $foo = $bar % 5 )
수학적인 기능은 오직 정수만 (.... -2, -1, 0, 1, 2 ....)만 가능하다는 점에 주의하라.
범위 연산 (Range Operator)
범위 연산은 #set과 #foreach 구문 사이에서 이용될 수 있다. 범위연산자는 다음의 구조를 가진다.
[n..m]
위 예제에서 n과 m은 모두 정수여야 한다. m이 큰지 n이 작은지는 문제가 되지 않는다. n과 m사이에서 반복문이 순환될 것이기 때문이다.
다음은 범위연산의 사용 예제를 보여주고 있다.
First example:
#foreach( $foo in [1..5] )
$foo
#end
Second example:
#foreach( $bar in [2..-2] )
$bar
#end
Third example:
#set( $arr = [0..1] )
#foreach( $i in $arr )
$i
#end
Fourth example:
[1..3]
결과는 아래와 같다.
First example:
1 2 3 4 5
Second example:
2 1 0 -1 -2
Third example:
0 1
Fourth example:
[1..3]
Velocity 문법(매크로)
매크로
명령어 #macro는 VTL 템플릿에서 반복되는 문장을 정의하는데 사용된다.
매크로는 간단하고 복잡한 시나리오 모두에서 매우 유용하게 쓰인다. 매크로는 keystrokes를 저장하고 typographic error를 최소화할 목적으로 만들어졌다.
#macro( d )
<tr><td></td></tr>
#end
위 예제에서 정의되는 Velocimacro는 d 이다. 이 매크로는 아래와 같은 방법으로 호출된다.
#d()
이 템플릿이 불려질 때, Velocity는 아래와 같은 결과로 #d()를 대체하게 된다.
<tr><td></td></tr>
또한 Velocimacro는 인자의 수를 취할 수도 있다. 심지어 앞선 예제에서 보여진 zero argument 조차 하나의 옵션이다.
그러나 Velocimacro가 불려질 때, 그것은 정의된 수만큼의 argument와 함께 불려야 합니다. 많은 Velocimacros는 위에서 정의된 하나보다 더 많이 관련됩니다. 여기 색과 array, 두 개의 argument를 취한Velocimacro가 있습니다.
#macro( tablerows $color $somelist )
#foreach( $something in $somelist )
<tr><td bgcolor=$color>$something</td></tr>
#end
#end
이 예제에서 정의되는 매크로, #tablerow는 두 개의 argument를 취한다. 첫번째 argument는 $color를 대체하고 두번째 argument는 $somelist를 대체하게 된다.
VTL 템플릿 안으로 넣어질 수 있는 것은 모두 매크로 안으로 지정될 수 있다. 위에서 #tablerows 매크로는 foreach 명령어를 사용했다. #tablerows 매크로 정의를 보면 두개의 #end 명령이 있다. 예상하겠지만 첫번째는 #foreach에 속하고, 두번째는 매크로 정의를 마치는데 사용되는 것이다.
아래에 위에서 정의한 #tablerow 매크로를 사용하는 예제가 나온다.
#set( $greatlakes = ["Superior ","Michigan ","Huron","Erie ","Ontario "] )
#set( $color = "blue" )
<table>
#tablerows( $color $greatlakes )
</table>
변수 $greatlakes가 $somelist를 대체함에 유의하면서 아래 결과를 살펴보자.
<table>
<tr><td bgcolor="blue">Superior </td></tr>
<tr><td bgcolor="blue">Michigan </td></tr>
<tr><td bgcolor="blue">Huron</td></tr>
<tr><td bgcolor="blue">Erie </td></tr>
<tr><td bgcolor="blue">Ontario </td></tr>
</table>
매크로는 하나의 Velocity 템플릿 안에서 inline으로 정의될 수 있으나 이렇게 정의한 매크로는 다른 템플릿에서는 사용할 수 없다. 매크로가 모든 템플릿들에 공유될 수 있도록 정의하기 위해서 velocity.properties 설정파일 내에 template library (velocimacro.library)를 지정하도록 한다.
공유되는 매크로의 이점은 많은 템플릿 들에서 매크로를 재정의할 필요를 줄여 작업량을 줄이고, 오류가 발생할 수 있는 기회를 줄인다는 점이다.
매크로 인자 (Arguments)
매크로에 정의되는 argument는 다음의 VTL 요소들을 모두 취할 수 있다.
Reference : anything that starts with '$'
String literal : something like "$foo" or 'hello'
Number literal : 1, 2 etc
IntegerRange : [ 1..2] or [$foo .. $bar]
ObjectArray : [ "a", "b", "c"]
boolean value true
boolean value false
velocity.properties에서의 매크로 관련 설정
velocimacro.library - 콤마(,)로 구분된 모든 템플릿 라이브러리 목록. VM_global_library.vm.설정된 template path가 Velocimacro library를 찾는데 사용됩니다.
velocimacro.permissions.allow.inline - true(기본값)/false. 이 속성은 매크로가 표준 템플릿 내에서 inline으로 정의될 수 있는지를 결정한다.
velocimacro.permissions.allow.inline.to.replace.global - true/false(기본값). 만약 템플릿 내에서 inline으로 정의된 매크로가 velocimacro.library에 설정된 라이브러리의 매크로를 대체할 지를 설정한다. 만약 false라면 템플릿에 inline으로 정의된 매크로가 컨테이너 구동시 로드된 라이브러리의 매크로를 교체하는 것을 막는다.
velocimacro.permissions.allow.inline.local.scope - true/false(기본값). 이 속성은 inline으로 정의된 매크로가 정의하는 template에 대해 'visible'인지 아닌지를 조절한다. 이 속성을 true로 하면, 템플릿은 단지 정의되는 템플릿에 한해서만 유용한 inline VM을 정의할 수 있게 된다.
velocimacro.context.localscope - true/false(기본값). true라면 매크로를 통한 #set() 명령으로 문맥의 모든 modification이 매크로에 대해 'local'로 고려되며 영구적으로 영향을 끼치지 않게 된다.
velocimacro.library.autoreload - true/false(기본값). 이 속성은 자동 로드되는 매크로를 조절한다. true로 설정되면 요청된 매크로에 대한 원본 매크로 설정파일의 변화를 체크하여 필요시 해당 매크로를 리로드한다. 이것은 컨테이너 재기동 없이 매크로 라이브러리를 바꾸고 테스트 하도록 해준다. 이 모드는 오직 caching이 resource 안에서 off일때만 작동한다. (예 : file.resource.loader.cache = false). 이 속성은 운영단계가 아닌 개발단계에서만 사용하도록 권장한다.
매크로의 인자로서 다른 매크로나 디렉티브(명령어)를 이용할 수 있나?
다음 처럼 말이다.
#center( #bold("hello") )
그럴 수 없다. 이 명령은 타당하지 않다.
그러나 당신은 아래 예제처럼 이 문제를 우회하여 해결할 수 있다.
#set($stuff = "#bold('hello')" )
#center( $stuff )
#center( "#bold( 'hello' )" )
결과는 동일하다.
다른 예제를 살펴보자.
#macro( inner $foo )
inner : $foo
#end
#macro( outer $foo )
#set($bar = "outerlala")
outer : $foo
#end
#set($bar = 'calltimelala')
#outer( "#inner($bar)" )
결과는 아래와 같다.
outer : inner : outerlala
어떻게 문자열을 연결해야 하나?
당신은 단순히 연결해야 할 문자열들을 같이 놓으면 된다. 아래 예제를 통해 살펴보라.
#set( $size = "Big" )
#set( $name = "Ben" )
The clock is $size$name.
#set( $size = "Big" )
#set( $name = "Ben" )
#set($clock = "$size$name" )
The clock is $clock.
#set( $size = "Big" )
#set( $name = "Ben" )
#set($clock = "${size}$name" )
The clock is $clock.
결과는 모두 동일하게 "The clock is BigBen'이 된다.
프레임워크 내장 객체의 사용
TDF2에서 지원하는 Velocity 템플릿에서 사용가능한 내장 객체 레퍼런스를 소개한다.
$actionInstanceVariable
$req - 현재 HttpServletRequest
$res - 현재 HttpServletResponse
$stack - 현재 OgnlValueStack
$ognl - OgnlTool
$webwork - WebWorkUtil 인스탄스
$action - 현재 WebWork action
$taglib (또는 이와 유사한 것) - Velocity 매크로를 통한 JSP tag 라이브러리에 접근 가능
$actionInstanceVariable
당신이 만든 Action 클래스의 멤버변수들에 대해 $actionInstanceVariableName 으로써 Velocity 템플릿이 접근할 수 있도록 해준다.
만약 당신의 Action 클래스에서 아래와 같은 멤버변수를 가진다고 하자.
public class ProcessEditTableRowAction extends ActionSupport {
private String fooString;
....
public String getFooString() {
return fooString;
}
....
이 경우, Velocity 템플릿에서 아래와 같은 레퍼런스를 통해 위 멤버변수의 값을 꺼낼 수 있다.
$fooString
$req
당신이 사용하는 서블릿 환경(Tomcat, Resin, etc....)에서 생성되어 관리되는 현재의 HttpServletRequest 인스탄스
$res
당신이 사용하는 서블릿 환경(Tomcat, Resin, etc....)에서 생성되어 관리되는 현재의 HttpServletResponse 인스탄스
$stack
com.opensymphony.xwork.util.OgnlValueStack 인스탄스
$ognl
com.opensymphony.webwork.views.jsp.ui.OgnlTool 인스탄스
Jason/Patrick에 의하면, OgnlTool은 static한 클래스 멤버에 접근할 수 있는 아주 멋진 Tool이다. Velocity에서는 Context에 설정되지 않은 클래스 변수나 메소드에 접근하는 기능을 제공하지 않는다. 그래서 당신은 템플릿 내에서 다음과 같은 메소드를 호출할 수 없다.
$java.lang.Math.random()
그러나 $ognl을 이용하면 아래와 같은 구문이 가능해진다.
$ognl.findValue("@java.lang.Math@random()")
$webwork
com.opensymphony.webwork.util.WebWorkUtil 인스탄스
Mathew에 따르면 $webwork는 다른 객체를 인스탄스화(초기화)할 수 있는 기능을 제공한다. Velocity에서는 Context에 설정되지 않은 객체를 초기화하는 방법을 제공하지 않기 때문에 이 기능은 매우 유용하다.
객체를 초기화하기 위해 당신은 템플릿 내에서 다음과 같은 문장을 사용할 수 있다.
#set($object = $webwork.bean("com.foo.ClassName"))
$action
현재 템플릿을 호출한 Action 컨텍스트의 인스탄스
$taglib
TDF2에서는 웹 디자이너와의 혼선을 피하기 위해 taglib 사용을 권장하지 않는다. 대부분의 지원 태그가 폼(form)과 관련된 내용이고, 이것의 사용으로 많은 이점을 제공한다고 보기 어렵기 때문에 TDF2에서는 가급적 익숙한 HTML 표준 폼 태그를 이용하기를 권장한다.
$taglib에 대한 자세한 정보를 알고 싶다면 http://wiki.opensymphony.com/display/WW/UI+Tags?showChildren=true#children를 방문하라.
'Dev. 웹' 카테고리의 다른 글
개발자에게 유용한 사이트 정보 (0) | 2015.09.01 |
---|---|
[Markdown] 마크다운 사용하기 (0) | 2015.08.07 |
[Custom Tag] custom tag 작성 중 SimpleTagSupport 에서의 세션 가져오기 (0) | 2014.10.28 |
오류 해결] IE에서 WrongDocumentError 발생 원인 및 해결 방법 (3) | 2014.10.24 |
JSTL (JSP Standard Tag Library) 시작하기 - 이해 및 실습 (0) | 2014.10.14 |