GAEでSpringMVCを動かしてみる2(テンプレートエンジンVelocityを組込む)

GoogleAppEngineの勉強中です。
前回のエントリーで、SpringMVCを動かしてみました。
その時は、ひとまずjspで画面表示していたけど、今回は、テンプレートエンジンのApache Velocity を使って、「SpringMVC + Velocity」を試してみます。
とりあえず動かすことを目標にしているので、テンプレートの分割(ヘッダ、フッタ、コンテンツ、サイドバー領域とか)まではやりません。

————————————————————–
使っている環境
Java JDK1.6.0_35(64bit版)
Google App Engine SDK for Java 1.7.1

Eclipse IDE for Java EE Developers_ Juno (4.2)64Bit版
The Google Plugin for Eclipse, for Eclipse 3.8/4.2 (Juno)

Spring Framework 3.2.2.RELEASE
Commons Collections 3.2.1
Commons Lang 2.6
Commons Logging 1.1.2
Apache Velocity 1.7


(1)はじめに

テンプレートエンジンって、そもそも、どれ使えばいいのか謎。
このページに一覧が載ってるけど、すげーたくさんある。
Template engine (web) – Wikipedia, the free encyclopedia

今回は、Springと連携させる、ってことで、以下のサイトを参考にしました。
(a)SpringMVCで使えるテンプレートエンジンを比較してみた #jsug – from world import goodies
(b)Template Engineの比較(Java) – No Bugs, No Life

上記サイトを見た感じだと、
・Velocity
・Freemarker
・Thymeleaf
・Mayaa

といったものが候補になりそう。(JSPはテンプレートの分割ができないと思うので最初から除外(タグを使えばできる?))

また、SpringFrameworkのドキュメントの「18. View technologies」にテンプレートのことが書かれてあるのを見つけました。
その中の、「18.4. Velocity & FreeMarker」で、Velocity 、FreeMarkerの説明があるので、この2つのうちどちらかがよさそう。
18. View technologies

で、先述したサイト(b)に記載があるんですが、FreeMarkerについては、現時点の最新版FreeMarker 2.3.19に、セキュリティの問題があるらしい。
FreeMarker Manual – 2.3.19

Attention! This release contains two important security workarounds that unavoidably make it obvious how some applications can be exploited. FreeMarker can’t solve these issues on all configurations, so please read the details instead of just updating FreeMarker!

というわけで、Velocityを使うのが無難そう。


(2)SpringFramework、Commons Loggingのダウンロード
こちらについては、前回のエントリーに書いてあるのでそちらを参照してください。
GAEでSpringMVCを動かしてみる | Walk on apps.


(3)velocityのダウンロード
こちらのサイトのDownloadsから入手できます。
Apache Velocity Site – The Apache Velocity Project

僕の場合、velocity-1.7.tar.gz をダウンロードしました。


(4)Commons Collectionsのダウンロード
こちらのサイトのDownloadsから入手できます。
Collections – Home

僕の場合、commons-collections-3.2.1-bin.tar.gz をダウンロードしました。


(5)Commons Langのダウンロード
こちらのサイトのDownloadsから入手できます。
Lang – Home

Commons Langについては、ちょっと注意です。
Commons Langがない状態でSpringMVCを起動すると、Class Not Foundエラーが出ます。原因は以下のClassでした。
org.apache.commons.lang.StringUtils

が、現時点での最新版、commons-lang3-3.1を使うとこのエラーが解消しません。JavaDocを見ると
version 3.*ではクラス名が微妙に違っているみたいでした。
extended by org.apache.commons.lang3.StringUtils

なので、version2.*系の最新版、commons-lang-2.6-bin.tar.gz をダウンロードしました。


(6)ライブラリ追加
ライブラリに追加するjarファイルは、以下の11個
commons-collections-3.2.1.jar
commons-lang-2.6.jar
commons-logging-1.1.2.jar
spring-beans-3.2.2.RELEASE.jar
spring-context-3.2.2.RELEASE.jar
spring-context-support-3.2.2.RELEASE.jar
spring-core-3.2.2.RELEASE.jar
spring-expression-3.2.2.RELEASE.jar
spring-web-3.2.2.RELEASE.jar
spring-webmvc-3.2.2.RELEASE.jar
velocity-1.7.jar

これらのjarファイルを、Eclipseの“war/WEB-INF/lib”フォルダに、配置します。
spring_velocity01

また、Eclipseの、「Java Build Path」に追加します。
spring_velocity02


(7)コーディング

まずは、Controllerを作成します。
Controllerの書き方は、こちらのサイトを参考にしました。
Spring-MVCとVelocityを使った Twitterライクに REST風な URLハンドリングをするサイトのテンプレート

書き方としては、Velocityを使わなかった時と変わらない書き方で大丈夫そう。(今回は、新規作成したので、前回のエントリーで作成したものと若干ちがっています。)
おそらく、SpringMVCでは、テンプレートエンジンに依存しない書き方ができるように設計されているんだと思った。

今回は、リクエスト「/velocity/***」に対して、テンプレートsample.vmを返す想定にしています。
model.addAttributeメソッドでテンプレートに引き渡す値をセットし、return “sample”;でテンプレートを指定しています。
テンプレートの置き場所や、ファイル名の拡張子については、SpringのBean定義ファイルの中で定義しています。

File名:src/sample/controller/VelocityController.java

package sample.controller;

import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

@Controller
@RequestMapping("/velocity")
public class VelocityController {

    //DI via Spring
    String message;

    @RequestMapping(value="/{name}", method = RequestMethod.GET)
    public String getMovie(@PathVariable String name, ModelMap model) {

        model.addAttribute("name", name);
        model.addAttribute("message", this.message);

        //return to .vm page, configured in mvc-dispatcher-servlet.xml, view resolver
        return "sample";
    }

    public void setMessage(String message) {
        this.message = message;
    }

}

次に、テンプレート(.vmファイル)を作成します。

リクエスト「/velocity/***」を受け取ったControllerが、***の部分を抜き出して、name変数に入れて、テンプレートに引き渡しています。

message変数は、SpringのBean定義ファイルの中でControllerに対して初期設定しています。Controllerがその値をテンプレートに引き渡しています。

File名:war/WEB-INF/view/sample.vm

<html>
<body>
name: ${name}<br/>
message: ${message}<br/>
</body>
</html>

次に、SpringのBean定義ファイルを作成します。
Bean定義ファイルについては、前回のエントリーで作成したものに追記し、不要な部分をコメントアウトしています。

<bean class=”sample.controller.MovieController”>の部分は、今回関係ないので読み飛ばしてください。

<bean class=”sample.controller.VelocityController“>のところで、コントローラの初期設定をしています。

「bean id=”velocityConfig“」と、「bean id=”viewResolver“」のところで、テンプレートファイルの置き場所・拡張子を指定しています。(複数のディレクトリを使い分けることは、できるんだろうか?)

File名:war/WEB-INF/mvc-dispatcher-servlet.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
                        http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
                        http://www.springframework.org/schema/context
                        http://www.springframework.org/schema/context/spring-context-3.2.xsd
                        http://www.springframework.org/schema/mvc
                        http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd
                        ">

<!--
    <context:component-scan base-package="sample.controller">
        <context:exclude-filter type="regex"
            expression="sample.controller.Movie.*" />
    </context:component-scan>
-->

    <mvc:annotation-driven />

    <!-- Bean to show you Di in GAE, via Spring, also init the MovieController -->
    <bean class="sample.controller.MovieController">
        <property name="message">
            <value>Hello World</value>
        </property>
    </bean>

<!--
    <bean
       class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix">
            <value>/pages/</value>
        </property>
        <property name="suffix">
            <value>.jsp</value>
        </property>
    </bean>
-->

    <bean class="sample.controller.VelocityController">
        <property name="message">
            <value>Velocity Sample</value>
        </property>
    </bean>

    <bean id="velocityConfig" class="org.springframework.web.servlet.view.velocity.VelocityConfigurer">
        <property name="resourceLoaderPath" value="/WEB-INF/view/"/>
    </bean>

    <bean id="viewResolver" class="org.springframework.web.servlet.view.velocity.VelocityViewResolver">
        <property name="cache" value="true"/>
        <property name="prefix" value=""/>
        <property name="suffix" value=".vm"/>
    </bean>

</beans>

次に、web.xmlを修正します。
web.xmlは、前回のエントリーで作成したときと同じ状態です。

リクエストをすべて、DispatcherServletに渡す、って感じ。と、Bean定義ファイルの場所を指定
ContextLoaderListenerは・・・なんだろ。。。。

File名:war/WEB-INF/web.xml

<?xml version="1.0" encoding="utf-8" standalone="no"?><web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.5" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">

    <servlet>
        <servlet-name>mvc-dispatcher</servlet-name>
        <servlet-class>
                    org.springframework.web.servlet.DispatcherServlet
                </servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>mvc-dispatcher</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>

    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/mvc-dispatcher-servlet.xml</param-value>
    </context-param>

    <listener>
        <listener-class>
                    org.springframework.web.context.ContextLoaderListener
                </listener-class>
    </listener>

    <welcome-file-list>
        <welcome-file>index.html</welcome-file>
    </welcome-file-list>

</web-app>

作成したソースコードの配置場所をまとめると、こんな感じになっています。

spring_velocity03


(8)アプリ起動
ブラウザから、アクセスするとこんな感じ。
spring_velocity04

リクエストで、/velocity/*** としたときの、***の部分が、
ブラウザ画面上で「name: ***」と表示されます。

上記の画面キャプチャは、自分のPC上(開発環境)のものですが、GAE上に実際にDeployしてもきちんと動きました。

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s