Velocity를 이용한 뷰 구현


  □ Velocity
    ■ 정의
      - 템플릿 엔진.
    ■ 특징
      - 템플릿 파일을 비교적 쉽게 작성 가능.
      - 자바 객체를 템플릿 파일에서 조작할 수 있기 때문에 뷰를 생성하는데 JSP 만큼 널리 사용.

  □ VelocityViewResolver와 VelocityConfigurer를 이용한 Velocity 연동
    ■ VelocityViewResolver
      - 스프링에서 Velocity를 연동할 때에 사용.
      - Velocity 템플릿 파일을 이용해서 뷰를 생성.
      - VelocityConfigurer를 사용해서 Velocity와 관련된 설정 정보를 입력.
      - VelocityConfigurer에서 설정한 경로에서 템플릿 파일을 읽어와 뷰를 생성.
      - prefix 프로퍼티와 suffix 프로퍼티는 뷰 이름으로부터 템플릿 파일의 경로를 생성할 때 사용.
    ■ VelocityConfigurer
      ○ resourceLoaderPath 프로퍼티
        - 템플릿 파일을 로딩할 경로를 입력.
      ○ velocityProperties 프로퍼티
        - Velocity 설정 정보를 지정.
    ■ 설정
 <bean id="velocityConfigurer"
    class="org.springframework.web.servlet.view.velocity.VelocityConfigurer">
    <property name="resourceLoaderPath" value="/WEB-INF/viewvm/" />
    <property name="velocityProperties">
        <props>
            <prop key="input.encoding">EUC-KR</prop>
            <prop key="output.encoding">EUC-KR</prop>
        </props>
    </property>
 </bean>

 <bean id="viewResolver"
    class="org.springframework.web.serlvet.view.velocity.VelocityResolver"
    p:suffix=".vm" p:contentType="text/html; charset="EUC-KR" />
         - 컨트롤러가 리턴한 뷰 이름이 "hello"라면 실제 사용되는 템플릿 파일은 "/WEB-INF/viewvm/hello.vm"이 됨.
    ■ 템플릿 파일
      - 템플릿 파일에서는 ModelAndView 객체에 저장된 모델 정보를 사용 가능.
      ○ 컨트롤러
 @Override
 protected ModelAndView handleRequestInternal(HttpServletRequest request, 
    HttpServletResponse response) throws Exception {

    ModelAndView mav = new ModelAndView();
    mav.setViewName("hello");
    mav.addObject("greeting", getGreeting());
    mav.addObject("me", me);

    return mav;
 }
      ○ 템플릿 파일
 <html>
 
 <head>
    <meta http-equiv="Content-Type" content="text/html; charset=EUC-KR">
    <title>인사</title>
 </head>
 
 <body>
    전 ${me}입니다. ${greeting}
 </body>

 </html>
    ■ Velocity Tools의 NumberTool과 DateTool 설정
      - Veloctiy는 템플릿 파일에서 유용하게 사용할 수 있는 기능인 다양한 툴을 제공하는 Velocity Tools를 제공.
      - 숫자와 날짜를 형식에 맞게 출력해주는 NumberTool과 DateTool을 제공.
      ○ VelocityViewResolver에서 제공하는 프로퍼티
        - dateToolAttribute : DateTool에 접근할 때 사용할 변수명을 지정.
        - numberToolAttribute : NumberTool에 접근할 때 사용할 변수명을 지정.
      ○ 설정
 <bean id="viewResolver"
    class="org.springframework.web.servlet.view.velocity.VelocityViewResolver"
    p:suffix=".vm" p:contentType="text/html; charset=EUC-KR"
    p:dateToolAttribute="dateTool" p:numberToolAttribute="numberTool" />
      ○ 사용 예
 <html>

 <head>
    <meta http-equiv="Content-Type" content="text/html; charset=EUC-KR">
    <title>#springMessage("title.currentTime")</title>
 </head>

 <body>
    #springMessage("lagel.currentTime")
    :$dateTool.format("yyyy-MM-dd HH:mm:ss". $time)
 </body>

 </html>
    ■ request 및 session 속성 템플릿 파일에서 사용하기
      ○ request 및 session 속성을 템플릿에 전달하기 위한 VelocityViewResolver 프로퍼티
        - exposeRequestAttributes : 프로퍼티 값을 true 로 지정. (기본값 : false)
        - exposeSessionAttributes : 프로퍼티 값을 true 로 지정. (기본값 : false)
      ○ 설정
 <bean id="viewResolver"
    class="org.springframework.web.servlet.view.velocity.VelocityViewResolver"
    p:suffix=".vm" p:contentType="text/html; charset=EUC-KR"
    p:dateToolAttribute="dateTool" p:numberToolAttribute="numberTool"
    p:exposeRequestAttributes="true" p:exposeSessionAttributes="true" />

  □ 스프링이 제공하는 Velocity 매크로
    ■ 설정
      - 입력 폼을 위한 HTML 태그와 에러 메시지 등을 생성할 때 매크로를 유용하게 사용.
      - exposeSpringMacroHelpers 프로퍼티의 값을 true로 지정. (스프링 2.5의 경우는 기본 값이 true)
 <bean id="viewResolver"
    class="org.springframework.web.servlet.view.velocity.VelocityViewResolver"
    ...
    p:exposeRequestAttribute="true" p:exposeSessionAttributes="true"
    p:exposeSpringMacroHelpers="true" />
    ■ 메시지 출력을 위한 #springMessage 매크로와 #spring MessageText 매크로
      - 스프링의 MessageSource로부터 메시지를 읽어와 출력할 때 사용.
      ○ 정의
        ● springMessage(code)
          - 코드에 해당하는 메시지를 출력.
          - 메시지가 존재하지 않을 경우 예외가 발생.
        ● springMessageText(code text)
          - 코드에 해당하는 메시지를 출력.
          - 메시지가 존재하지 않을 경우 text를 출력.
      ○ 사용 예
 <p>
    <label for="id">#springMessage("login.form.id")</label>
    #springFormInput("login.id" "")
    #springShowErrors("<br/>" "")
    #springMessageText("login.form.id.help". "도움말이 없습니다.")
 </p>
         - #springMessage 매크로는 login.form.id 메시지 코드에 해당하는 메시지를 출력.
         - #springMessageText 매크로는 login.form.id.help 메시지 코드에 해당하는 메시지를 출력. 해당 메시지가 존재하지 않으면
           "도움말이 없습니다"를 대신 출력.
    ■ 커맨드 객체 연동을 위한 #springBind 매크로와 #springBindEscaped 매크로
      ○ #springBind 매크로
        - 커맨드 객체와 관련된 BindStatus 정보를 설정.
        - 커맨드 객체와 관련된 경로를 설정하고 관련 BindStatus 정보는 status 변수를 통햇 접근 가능.
      ○ #springBind 매크로 사용 예
 <p>
    <label for="id">#springMessage("login.form.id")</label>
    #springBind("login.id")
    <input type="text" name="${status.expression}" id="${status.expression}"
        value="$!status.value" />
    #springShowErrors("<br/>" "")
 </p>
         - login 커맨드 객체의 id 프로퍼티를 #springBind 매크로를 사용해서 바인딩.
         - id 프로퍼티와 관련된 BindStatus 객체는 status 변수를 통해서 접근 가능.
         - status.expression은 "id"를 출력.
         - status.value는 login 커맨드 객체의 id 프로퍼티의 값을 출력.
      ○ status 변수
        ● status.expression
          - BindStatus 객체와 연관된 커맨드 객체의 경로를 출력.
        ● status.value
          - 커맨드 객체와 관련된 값을 출력.
          - defaultHtmlEscape 컨텍스트 파라미터의 값에 따라 HTML 특수 문자 처리 여부를 결정.
      ○ #springBindEscaped 매크로
        - HTML 특수 문자 처리 여부를 직접 명시.
 <p>
    <label for="id">#springMessage("login.form.id")</label>
    #springBindEscaped("login.id" false)
    <input type="text" name="${status.expression}" id="${status.expression}"
        value="$!status.value" />
    #springShowErrors("<br/>" "")
 </p>
         - springBindEscaped 매크로의 두 번째 파라미터는 특수 문자를 치환할지의 여부를 설정. 
         - false 이므로 특수 문자를 변환하지 않도록 설정.
    ■ <input> 태그를 위한 매크로
      ○ #springFormInput 매크로
        - 커맨드 객체와 관련된 <input> 태그를 손쉽게 출력.
      ○ #springFormInput 매크로 정의
 #springFormInput($path $attributes)
        ● $path
          - <input> 태그를 생성할 때 사용할 커맨드 객체의 경로.
        ● $attributes
          - <input> 태그에 삽입할 HTML 속성 설정.
      ○ 사용 예
 <label for="name">이름</label>
 #springFormInput("memberInfo.name" "class="input")
 #springShowErrors("<br/>" "")
         - #springFormInput 매크로는 memberInfo 커맨드 객체의 name 프로퍼티와 관련된 <input> 태그를 생성.
      ○ hidden 타입의 <input> 태그나 password 타입의 <input> 태그 생성
        ● #springFormPasswordInput($path $attributes)
          - password 타입의 <input> 태그를 생성.
          - 사용 방법은 #springFormInput 매크로와 동일.
        ● #springFormHiddenInput($path $attributes)
          - hidden 타입의 <input> 태그를 생성.
          - 사용 방법은 #springFormInput 매크로와 동일.
      ○ #springBind 매크로를 사용하여 커맨드 객체와 관련된 BindStatus 정보 설정
        - 내부적으로 #springBind 매크로를 사용해서 커맨드 객체와 관련된 BindStatus 정보에 접근.
 #macro(springFormInput $path $attributes)
    #springBind($path)
    <input type="text" id="${status.expression}" name="${status.expression}"
        value="$!status.value" ${attributes}#springCloseTag()
 #end
         - 폼과 관련된 모든 매크로는 위 코드와 같이  #springBind 매크로를 이용해서 커맨드 객체와 관련된 BindStatus 정보를 설정.
    ■ <select> 태그를 위한 매크로
      ○ <select> 태그와 관련한 매크로
        ● #springFormSingleSelect($path $options $attributes)
          - 한 개의 옵션을 선택할 수 있는 <select> 태그를 생성.
          - $options : <option> 태그를 생성할 때 사용할 Map 객체를 지정.
          - $attributes : HTML 태그의 속성 설정을 입력.
        ● #springFormMultiSelect($path $options $attributes)
          - 다중 선택이 가능한 <select> 태그를 생성.
          - $options : <option> 태그를 생성할 때 사용할 Map 객체를 지정.
          - $attributes : HTML 태그의 속성 설정을 입력.
      ○ 사용 예
 Map<String, String> jobCodes = new HashMap<String, String>();
 jobCodes.put("1", "개발자");
 jobCodes.put("2", "UI 개발자");
 jobCodes.put("3", "웹 디자이너");
 jobCodes.put("4", "기획자");

 ModelAndView mav = new ModelAndView();
 mav.addObject("jobCodes", jobCodes);
 <label for="jobCode">직업</label>
 #spriingFormSingleSelect("memberInfo.jobCode" $jobCodes "")
 #springShowErrors("<br/>" "")
      ○ #springFormSingleSelect 매크로
        - $options에 전달받은 Map 객체의 키를 <option> 태그의 value 속성의 값으로 사용.
        - Map 객체의 값을 <option> 태그의 텍스트로 사용.
      ○ List 객체를 이용해서 <option> 태그 생성
        - #springBind 매크로를 이용해서 직접 <select> 태그와 <option> 태그를 생성.
 #springBind("login.loginType")
 <select id="${status.expression}" name="${status.expression}">
    #foreach($option in $loginTypes)
        <option value="${option}"
        #if("$!status.value" == "$option")
            selected="selected"
        #end
        $option</option>
    #end
 </select>
    ■ checkbox 타입 <input> 태그를 위한 매크로
      ○ checkbox 타입을 위한 <input> 태그 생성 매크로
        ● #springFormCheckboxes($path $options $separator $attributes)
          - $options : checkbox 타입의 <input> 태그를 생성할 때 사용할 Map 객체를 전달 받음.
          - $separator : 각각의 선택 항목을 구분하기 위한 구분자를 입력
      ○ 사용 예
 Map<String, String> favoritesOsNames = new HashMap<String, String>();
 favoritesOsNames.put("WIN2000", "윈도우2000");
 favoritesOsNames.put("WINXP", "윈도우XP");
 favoritesOsNames.put("VISTA", "비스타");
 favoritesOsNames.put("UBUNTU", "우분투");
 favoritesOsNames.put("MAC", "맥");
 
 referenceData.put("favoritesOsNames", favoritesOsNames);
 <label for="favorites">선호 OS</label>
 #springFormCheckboxes("memberInfo.favorites" $favoritesOsNames " | " "")
 #springShowErrors("<br/>" "")
    ■ radio 타입 <input> 태그를 위한 매크로
      ○ radio 타입의 <input> 태그 생성 매크로
        ● #springFormRadioButtons($path $options $separator $attributes)
          - 사용 방법은 #springFormCheckboxes 매크로와 동일.
      ○ 사용 예
 <p>
    <label for="tool">주로 사용하는 개발툴</label>
    #springFormRadioButtons("memberInfo.tool" $tools "" "")
 </p>
    ■ <textarea> 태그를 위한 매크로
      ○ <textarea> 태그 생성 매크로
        ● #springFormTextarea($path $attributes)
      ○ 사용 예
 <p>
    <label for="etc">기타</label>
    #springFormTextarea("memberInfo.etc" "cols='20' rows='3'")
 </p>
    ■ 에러 메시지 출력을 위한 #springShowErrors 매크로
      ○ #springShowErrors 매크로
        - 커맨드 객체와 관련된 에러 메시지를 출력할 때 사용.
      ○ 정의
        ● #springShowErrors($separator $class/style)
          - #springBind/#springBindEscaped 매크로로 바인딩 도니 BindStatus와 관련된 에러 메시지들을 출력.
          - $separator : 각 에러 메시지를 구분할 때 출력되는 값.
          - $class/style : 각 에러 메시지를 위한 CSS 관련 정보를 설정할 때 사용.
      ○ 컨트롤러에서 생성한 에러 메시지 출력
 // 커맨드 객체와 관련된 에러 정보를 추가.
 errors.reject("invalidldOrPassword", new Object[] {loginCommand.getId()}, null);
 // 에러 메시지 출력
 #springBind("login")
 #springShowErrors("<br>" "")
      ○ 특정 프로퍼티와 관련된 에러 메시지 출력
        - #springBind 매크로를 사용하거나 폼 관련 매크로를 사용.
 <p>
    <label for="id">#springMessage("login.form.id")</label>
    #springBind("login.id")
    <input type="text" name="${status.expression}" id="${status.expression}"
        value="$!status.value" />
    #springShowErrors("<br/>" "")
 </p>
 <p>
    <label for="password">#springMessage("login.form.password")</label>
    #springFormPasswordInput("login.password" "")
    #springShowErrors("<br/>" "")
 </p>
        - 폼 입력을 위한 매크로는 #springBind 매크로를 사용하기 때문에 폼 관련 매크로 사용한 뒤에는 #springShowErrors 매크로를
          사용해서 입력 폼과 관련된 에러 메시지를 출력.
      ○ #springShowErros 매크로의 두 번째 파라미터($class/style) 값 처리
        ● 파라미터 값이 ""로 지정
          - 에러 메시지를 <b> 태그를 사용해서 강조.
 <b> 잘못된 ID나 암호를 입력하셨습니다. 입력한 ID는 124입니다. </b>
        ● CSS 관련 속성을 사용하여 에러 메시지 출력
          - CSS 관련 정보 입력.
          - ""이 아닐 경우 : <span> 태그를 이용해서 에러 메시지를 감싼다.
          - ":"로 시작할 경우 : <span>의 style 속성의 값을 두 번째 파라미터의 값으로 설정.
 #springFormInput("memberInfo.userId" "")
 #springShowErrors("<br/>" ":font-size:15pt;")
 // 에러 메시지는 두 번째 파라미터로 전달받은 값을 style 속성의 값으로 사용.
 <span style=":font-size:15pt; ">필수 항목입니다. </span>
          - ":"로 시작하지 않을 경우 : class 속성의 값을 두 번째 파라미터 값으로 설정.
 #springFormInput("memberInfo.name" "class='input'")
 #springShowErrors("<br/>" "error")
 // 에러 메시지는 두 번째 파라미터로 전달받은 값을 class 속성의 값으로 사용.
 <span class="error">필수 항목입니다. </span>
         
  □ VelocityLayoutViewResolver를 이용한 Velocity 레이아웃 템플릿 사용
    ■ VelocityLayoutServlet
      - Velocity Tools가 제공.
      - Velocity에서 동일한 레이아웃을 여러 페이지에 적용할 수 있도록 도와줌. (Tiles와 비슷)
      - 여러 Veloticy 템플릿 파일에서 레이아웃 처리를 위해 중복된 HTML 코드를 작성하지 않아도 됨.
    ■ VelocityLayoutViewResolver
      - VelocityLayoutServlet과 동일하게 하나의 레이아웃을 여러 템플릿 파일에 적용.
    ■ VelocityLayoutViewResolver를 이용한 레이아웃 템플릿 적용
      - 결과 화면을 생성해주는 View 클래스로 VelocityLayoutView 객체를 생성.
      - VelocityLayoutViewResolver를 ViewResolver로 사용하도록 설정.
      ○ 설정
 <bean id="velocityConfigurer"
    class="org.springframework.web.servlet.view.velocity.VelocityConfigurer">
    <property name="resourceLoaderPath" value="/WEB-INF/viewvmlayout/" />
    <property name="velocityProperties">
        ...
    </property>
 </bean>

 <bean id="viewResolver"
    class="org.springframework.web.servlet.view.velocity.VelocityLayoutViewResolver"
    p:layoutUrl="/template/layout.vm" 
    p:suffix=".vm" p:contentType="text/html; charset=EUC-KR" ... />
         - prefix나 suffix 등의 프로퍼티는 VelocityViewResolver와 동일.
         - layoutUrl 프로퍼티를 사용하여 레이아웃으로 사용될 Velocity 템플릿 파일을 지정.
      ○ 응답화면 생성
        - VelocityViewLayout 객체는 2단계 과정을 거쳐서 응답 화면 생성.
 1) 컨트롤러의 처리 결과를 보여 줄 템플릿 파일을 찾은 뒤, 템플릿 파일로부터 결과 화면을 생성. 이때 생성된 
     결과 화면을 screen_content 변수에 저장.
 2) layoutUrl 프로퍼티로 지정한 레이아웃 템플릿 파일을 파싱하여 결과 화면을 생성. 이때 레이아웃 템플릿 파일
     은 $screen_content 변수를 사용하여 1단계에서 생성한 결과 화면을 내부에 포함 시킴.

        - /greeting/hello.htm 요청을 처리한 뒤 그 결과를 /hello.vm 템플릿 파일을 통해서 출력할 경우 /hello.vm을 통해서 생성된 결과

          화면이 레이아웃으로 지정한 /template/layout.vm 템플릿 파일의 특정 영역에 삽입.
          (layout.vm이 포함하고 있는 레이아웃이 hello.vm의 출력 결과에 적용되는 것.)

    ■ Velocity 레이아웃 파일 생성
      ○ 레이아웃으로 사용될 Velocity 템플릿 파일과 일반 Velocity 템플릿 파일의 차이점
        - 처리 결과로 생성된 결과를 포함하기 위한 $screen_content 변수 사용.
 <html>
 
 <head>
    <meta http-equiv="Content-Type" content="text/html; charset=EUC-KR">
    <title>제목</title>
 </head>

 <body>
    #parse("/template/header.vm")
    <hr />
    $screen_content
    <hr />
    #parse("/template/footer.vm")
 </body>

 </html>
      ○ 특징
        - 다수의 요청에 대해서 동일한 레이아웃 템플릿 파일이 사용되기 때문에 모든 페이지가 동일한 레이아웃을 갖게 됨.
        - 각 요청의 처리 결과를 생성하는 Velocity 템플릿의 출력 결과는 $screen_content 변수에 위치.
        - Velocity의 #parse나 #include를 사용하면 다수의 레이아웃 템플릿 파일에서 사용되는 부분을 재사용.
      ○ 사용 예
        - 왼쪽 메뉴가 추가된 레이아웃.
 <html>

 <head>
    <meta http-equiv="Content-Type" content="text/html; charset=EUC-KR">
    <title>제목</title>
 </head>

 <body>
    #parse("/template/header.vm")
    <hr />
    <div id="left">#parse("/common/left_menu.vm")</div>
    <div id="content" class="content_side">
        $screen_content
    </div>
    <hr />
    #parse("/templat/footer.vm")
 </body>
 </html>
         - #parse를 사용하여 head.vm이나 top_logo.vm 등의 내용을 재사용.
    ■ 레이아웃 커스터마이징
      ○ 예
        - /a.htm 요청과 /b.htm 요청을 처리 결과를 각각 a.vm과 b.vm을 통해 생성.
        - 공통으로 사용되는 레이아웃으로 layout.vm을 사용.
        - layout.vm은 a.vm이나 b.vm에서 지정한 변수 사용 가능.
 /* a.vm 파일의 내용 */
 #set($htmlTitleTail = '카페')
 ...
 #foreach ($content in $contents)
 ...$content.title ...
 #end
 ...
 /* layout.vm의 내용 */
 <html>
    <title>세상을 즐겁게 변화시키는 DAUM
    #if($htmlTitleTail) : $htmlTitleTail #end</title>
    ...
    <body>
    ${screen_content}
    #parse("/common/bottom.vm")
 </html>   
         - a.vm은 $htmlTitleTail 변수의 값을 지정.
         - layout.vm은 $htmlTitleTail 변수가 존재할 경우 해당 값을 출력하는 코드를 갖고 있음.
         - a.vm이 먼저 파싱된 뒤 layout.vm이 파싱되고, 추가적으로 a.vm에서 정의한 변수를 layout.vm에서 사용할 수 있음.
        ● /a.htm의 요청 결과 HTML 코드
 <html>
    <title>세상을 즐겁게 변화시키는 DAUM : 카페 </title>
    ...
    <body>
    ...
    글제목1
    글제목2
    ...
      ○ 레이아웃의 일부 변경
        - 변수를 전달할 수 있는 기능을 사용하면 레이아웃의 일부 변경 가능.
        ● 레이아웃 템플릿 파일
 #if($headVm)
    #parse($headVm)
 #else
    #parse("/templat/head.vm")
 #end
 ...
         - $headVm 변수가 존재할 경우 변수에 해당하는 vm 파일을 파싱해서 포함.
         - $headVm 변수가 존재하지 않을 경우 "/template/head.vm"을 파싱해서 포함.
        ● /a.htm의 결과가 /template/head_wide.vm을 헤드로 사용
          - /a.htm의 처리 결과를 생성하는 a.vm 파일에서 $headVm 변수 값으로 '/template/head_wide.vm'을 지정.
 #set ($headVm = '/template/head_wide.vm')
 ...
      ○ 레이아웃 템플릿 자체 변경
        - $layout 변수에 레이아웃으로 사용할 템플릿 파일을 지정.
 #set($layout = "/template/layout_index.vm")
 ...

      ○ VelocityLayoutViewResolver 특징
        - Tiles나 Sitemesh 처럼 설정 파일을 사용하여 레이아웃을 관리할 수는 없지만, 레이아웃을 관리하는데 있어서 필요한 부분적인

           레이아웃의 변경, 전체 레이아웃의 변경과 같은 기능을 사용.

출처 : 
http://blog.naver.com/PostView.nhn?blogId=chocolleto&logNo=30087127522 

YOUR COMMENT IS THE CRITICAL SUCCESS FACTOR FOR THE QUALITY OF BLOG POST
  1. 꼬렙 2012.03.06 11:48 신고  댓글주소  수정/삭제  댓글쓰기

    이건 또 뭐고 -_-;;;
    김주임 희안한거 마이 하는구나