Showing posts with label Spring. Show all posts
Showing posts with label Spring. Show all posts

Wednesday, December 11, 2013

Spring MVCでThymeleafを使う

Thymeleafについて

ThymeleafはJSPに変わるような、主にHTML向けのテンプレートエンジン。JSPよりも高性能らしい。大きな特徴は、HTMLとしても妥当なマークアップでテンプレートを記述できること。同様のアプローチはSeasarファミリーにMayaaというのがあった。Mayaaはテンプレートのほかに、データとテンプレートのマッピング用のXMLを用意する必要があったのがイマイチだった。Thymeleafは普通にテンプレートファイルは一つで大丈夫。

ここではSTSのSpring MVCのテンプレートで作成したプロジェクトのテンプレートエンジンを、Thymeleafに変更する。

Mavenで依存を解決

pom.xmlのdependencyに以下を追加。

<dependency>
  <groupId>org.thymeleaf</groupId>
  <artifactId>thymeleaf</artifactId>
  <version>2.0.16</version>
</dependency>
<dependency>
  <groupId>org.thymeleaf</groupId>
  <artifactId>thymeleaf-spring3</artifactId>
  <version>2.0.16</version>
</dependency>
で、以下の(あるいは他の)コマンドを実行。
$ mvn install

Springの設定

Springの設定ファイルでテンプレートエンジンをJSPからThymeleafに変更。

<!-- 
<beans:bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
  <beans:property name="prefix" value="/WEB-INF/views/" />
  <beans:property name="suffix" value=".jsp" />
</beans:bean>
-->

<beans:bean id="templateResolver" class="org.thymeleaf.templateresolver.ServletContextTemplateResolver">
  <beans:property name="prefix" value="/WEB-INF/views/" />
  <beans:property name="suffix" value=".html" />
  <beans:property name="characterEncoding" value="UTF-8" />
  <beans:property name="templateMode" value="HTML5" />
  <beans:property name="cacheable" value="false"/>
</beans:bean>
<beans:bean id="templateEngine" class="org.thymeleaf.spring3.SpringTemplateEngine">
  <beans:property name="templateResolver" ref="templateResolver" />
</beans:bean>
<beans:bean class="org.thymeleaf.spring3.view.ThymeleafViewResolver">
  <beans:property name="characterEncoding" value="UTF-8" />
  <beans:property name="templateEngine" ref="templateEngine" />
</beans:bean>   

注意点としては、開発用にテンプレートのキャッシュを無効にしてある(デフォルトでは有効)。プロダクションにでプロイするときにはこの設定を有効にするべきでしょう。<beans:property name="cacheable" value="false"/>という箇所。

テンプレートを記述

あとはWEB-INF/views以下にテンプレートをThymeleafの書式で書いていくだけ。Spring MVCのコントローラからの呼び出し方法についてはJSPと全く同様。 ただし、テンプレートのHTMLには以下のような宣言が必要。Thymeleaf単体で利用するのとは違い、thymeleafに'-spring3'というサフィックスがつくのに注意。

<!DOCTYPE html SYSTEM "http://www.thymeleaf.org/dtd/xhtml1-strict-thymeleaf-spring3-3.dtd">

<p th:utext="#{home.welcome}">Welcome to our grocery store!</p>

Saturday, August 10, 2013

Spring MVCでアスペクト(インターセプター)を実装する

Spring MVCでアスペクト(インターセプター)を実装するのは結構簡単。アスペクトっていうのは、要するにメソッドに対して前後処理をするモジュールのこと。フィルターみたいなやつですね。Springの場合はSpring配下にある任意のクラスのメソッドに適応可能。アスペクトで実装する一番ありがちな処理はログでしょうね。私もそのために使いました。あとはエラー処理とか。

SpringではどうもAspect Jを使ってAOPをしていて、用語もそれに従っている。ここでは面倒なので細かい用語の説明はなし。気になる人はアドバイス、ポイントカット、ジョインポイントあたりについて調べるといいんじゃないでしょうか。もっと色々ありそうですけど。

アスペクトの種類

アスペクトには以下の種類がある。

  • Before : メソッドの処理の前
  • AfterReturning : メソッドの処理の後例外は除く)
  • AfterThrowing : メソッドで例外が発生したとき
  • After : メソッドの処理の後(例外も含む)
  • Around: メソッドの前後処理を記述
単純なログならBeforeやAfter*、処理時間の計測とかを含むならAround、っていうのがありがちのようですね。

アスペクトのクラスを実装

すごい簡単。アスペクトのクラスに@Aspect、インターセプターの処理のメソッドに、種類に応じて上記の名前のアノテーション(@Beforeとか)をつけるだけ。

例えば、Service層のクラスの中で、自作の@UpdateDatasourceというアノテーションのついているメソッドのみ特定のログを出力したいときの例。ここで、サービス層はorg.opentechnica.sample.serviceパッケージにあるとする。

アノテーションは普通に実装。

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface UpdateDatasource {
    public String value();
}

アスペクトも、アノテーション以外は普通に実装。

@Aspect
@Component
public class LoggingAspect {
    @Before("execution(public * org.opentechnica.sample.service..*(..))")
    public void before(JoinPoint jp) {
        try {
            Class targetClass = jp.getTarget().getClass();
            String methodName = jp.getSignature().getName();
            MethodSignature signature = (MethodSignature) jp.getSignature();
            Method method = signature.getMethod();

            UpdateDatasource updateDatasourceAnnotation = method
                    .getAnnotation(UpdateDatasource.class);
            if (updateDatasourceAnnotation != null) {
                Logger logger = Logger.getLogger(targetClass);
                logger.info("before");
            }
        } catch (SecurityException e) {
            // do nothing
        }
    }
}

@Beforeアノテーション

@Beforeアノテーションでメソッドの実行前にインジェクションする処理であることを表している。アノテーションの引数("execution(public * org.opentechnica.sample.service..*(..))")は、この処理を実行する対象をフィルタリングする条件。ポイントカットっていやつですね。ここでの指定は以下のような意味。

  • publicで
  • 任意の戻り値型で
  • org.opentechnica.sample.serviceパッケージ以下の任意のクラスの
  • 任意の引数を持つ

対象のメソッドが目的のアノテーションを持つかどうか調べる

Javaは同一のメソッド名でも引数が違うと違うシグニチャになるので普通のリフレクションだと面倒だけど、beforeメソッドに渡されるJoinPointから、以下のようMethodSignatureにキャストすると直接取得できる。

MethodSignature signature = (MethodSignature) jp.getSignature();
Method method = signature.getMethod();
で、methodがとれたらもうmethod.getAnnotation(UpdateDatasource.class)とすれば、自作の@UpdateDatasourceが付加されているかどうかわかる。

applicationContext.xmlでAOPの設定

アスペクトを実装したら、applicationContext.xmlに以下の一行を追加するだけで動く。便利!

<aop:aspectj-autoproxy/>