[Java Web programming] Velocity 사용하기

 

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 파일) 다음과 같은 패턴을 통해 처리 된다.

// 벨로시티 템플릿 엔진의 초기화
// 초기화 설정은 velocity.properties 파일을 사용함
Velocity.init("velocity.properties");

// 
자바 클래스와 템플릿간의 정보 전달에 사용할 컨텍스트 객체 생성
// 컨텍스트 객체는 해시 테이블을 상속받으므로 (키, 값)의 순서쌍 형태로 값을 저장 
// 예) context.put("members", memberDAO.getMembers()); 
// 이렇게 해서 컨텍스트에 저장된 값들은 템플릿에서 레퍼런스를 이용해서 참조됨
// 컨텍스트에 담긴 값이 컬렉션일 경우 #foreach 디렉티브를 통해 하나씩 참조 가능 
VelocityContext context = new VelocityContext();
Template template = null

// 
로직과 연결되어 사용될 템플릿 파일을 선택
template = Velocity.getTemplate("HelloWorld.vm");
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(System.out)); 

// 
템플릿과 컨텍스트를 렌더링해서 그 결과를 출력 
if ( template != null
  template.merge(context, writer);

writer.flush(); 
writer.close(); 

템플릿 엔진이 동작하는 방식을 정리해 보면, 개발자는 사용자에게 보여 디자인을 위해 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($)표시의 경우는 어떻게 하는가?

만약 당신이 페이지 내에서 "나는 농부의 가게에서 17072.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

경축! 아무것도 안하여 에스천사게임즈가 새로운 모습으로 재오픈 하였습니다.
어린이용이며, 설치가 필요없는 브라우저 게임입니다.
https://s1004games.com

*       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 방문하라.

 

출처: https://androphil.tistory.com/525 [소림사의 홍반장!:티스토리]

 

 

 

본 웹사이트는 광고를 포함하고 있습니다.
광고 클릭에서 발생하는 수익금은 모두 웹사이트 서버의 유지 및 관리, 그리고 기술 콘텐츠 향상을 위해 쓰여집니다.
번호 제목 글쓴이 날짜 조회 수
206 [Java Web programming] [Spring] WebFlux란 무엇인가? - 개념(특징), MVC와 비교, 사용 이유 file 졸리운_곰 2023.07.18 3
205 [Java Web programming] [Spring Boot + Vue.js] 게시판 만들기 - 에러 file 졸리운_곰 2023.04.07 3
204 [Java Web programming] [Spring Boot + Vue.js] 게시판 만들기 - 버튼 file 졸리운_곰 2023.04.07 6
203 [Java Web programming] [Spring Boot + Vue.js] 게시판 만들기 - Toast UI Editor, Viewer file 졸리운_곰 2023.04.07 4
202 [Java Web programming] [Spring Boot + Vue.js] 게시판 만들기 - Tooltip, Snackbar file 졸리운_곰 2023.04.07 2
201 [Java Web programming] [Spring Boot + Vue.js] 게시판 만들기 - 날짜, 시간, 날씨 file 졸리운_곰 2023.04.07 5
200 [Java Web programming] [Spring Boot + Vue.js] 게시판 만들기 - 구성 졸리운_곰 2023.04.07 8
199 [Java Web programming] [Spring Boot + Vue.js] 게시판 만들기 - 소개 file 졸리운_곰 2023.04.07 12
198 [Java Web programming] SpringBoot, Vue 연동하기 file 졸리운_곰 2023.01.30 11
197 [JSP] [jstl ] case when 중첩 방법 file 졸리운_곰 2023.01.24 2
196 [JSP] intelliJ로 JSP 프로젝트 생성, Servlet 실행해보기 file 졸리운_곰 2022.12.31 2
195 [JSP} Jsp 커스텀 태그라이브러리(Custom Tag Library Descriptor) 생성 및 사용 졸리운_곰 2022.12.07 6
194 [JSP] JSP 커스텀 태그(Custom Tag) - 태그파일 file 졸리운_곰 2022.12.07 4
» [Java Web programming] Velocity 사용하기 졸리운_곰 2022.08.11 6
192 [java html template engine] [Velocity] velocity 기본 문법 file 졸리운_곰 2022.08.10 2
191 [Java Web 프로그래밍] SPRING BOOT SSO 자료 정리 file 졸리운_곰 2022.07.27 9
190 [Spring] 스프링 tiles 사용하기! file 졸리운_곰 2021.10.17 25
189 [JSP][Java] [JSP] JSP 문법 구조 / include를 활용해 layout 나누기 file 졸리운_곰 2021.09.09 13
188 [SpringBoot] 타임리프(Thymeleaf) Thymleaf for template engine file 졸리운_곰 2021.09.05 9
187 [스프링부트] Spring Boot + Thymeleaf CRUD Example file 졸리운_곰 2021.09.03 12
대표 김성준 주소 : 경기 용인 분당수지 U타워 등록번호 : 142-07-27414
통신판매업 신고 : 제2012-용인수지-0185호 출판업 신고 : 수지구청 제 123호 개인정보보호최고책임자 : 김성준 sjkim70@stechstar.com
대표전화 : 010-4589-2193 [fax] 02-6280-1294 COPYRIGHT(C) stechstar.com ALL RIGHTS RESERVED