結構前に作っていたけど書いてなかったので、せっかくだし書いておく。こだわりを以下に列挙。
ビルド
今グイグイ来てるGradleにしてみた。色々見てると、Mavenでやった方がハマりどころは少なそうではあるが。
Gradle Wrapperの設定もしてあるので、ビルドは楽だと思う。
Mavenに比べてビルドは遅いので、--daemon
付けたり、ホットデプロイ駆使する必要がある。
設定ファイル
YAMLでやる方法もあるみたいだが、自分はapplication.properties
でやることにした。
Thymeleafの設定
キャッシュオフとテンプレートモードをLEGACYHTML5にする設定をした。尚、このためにnekohtmlを依存性に追加。
spring.thymeleaf.mode=LEGACYHTML5
spring.thymeleaf.cache=false
LEGACYHTML5ならテンプレートをxhtmlにする必要がない。(HTML5だとxhtmlとして正しくないとエラーが発生する。。)
最初はHTML5でやっていたのだが、結局デザイナーがxhtmlにし忘れたところを直したり、IEの一部コンディショナルコメントがdialectを使わないと効かなかったりして結構難儀した。(xhtml的にダメなやつがある)
http://forum.thymeleaf.org/Conditional-Stylesheets-and-Thymeleaf-s-XML-Parser-HTML5-tp3468198p4025036.html
デザイナーの本もパラパラと見てみたのだが、あまりxhtmlで説明されているものも少ないように感じたので、最近は方針転換してLEGACYHTML5派になった。
htmlとxhtml、動的言語と静的言語のような関係っぽい。
CSRF対策
依存関係にspring-boot-starter-securityを追加。
@ EnableWebMvcSecurityアノテーションが付いた設定クラスを用意。WebSecurityConfigurerAdapterを継承。
パスワード認証は要らないのでsecurityContextはdisableに。(雰囲気で書いてるのでSpring Securityについてもっと調べる。。)
package hello;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.annotation.web.servlet.configuration.EnableWebMvcSecurity;
@Configuration
@EnableWebMvcSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.securityContext().disable();
}
}
これだけでformタグ中にCSRFトークンがhiddenで含まれるようになる。
しかし注意点があって、ざっと試した感じだと、th:action
としてactionが書いてあるpostのformタグだけが自動挿入対象になるらしい。ただのaction
ではダメ。
尚、テンプレート中では_csrf
という変数で参照出来るらしい。
<p th:text="${_csrf.token}"></p>
画面を表示してソースを見るとCSRFトークンが設定されていることが確認出来る。
CSRFトークンを改ざんしてリクエストすると403エラーになることを確認。チェックは透過的にSpring Securityによって行われている模様。
JavaScriptなどの静的コンテンツ
やり方は設定と同じく数パターンあるみたいだが、src/main/resources
にstaticディレクトリを作ってそこに置くことにした。
i18n
src/main/resources/i18n
にi18n用のメッセージファイルを置くようにした。
ja_JPとen用のファイルを配備。
Spring Data JPAでデータベースアクセス
依存関係にspring-boot-starter-data-jpa、H2Databaseを追加。
トランザクション境界はServiceアノテーションが付いたクラスから始まるようにし、チェック例外も含め、例外が発生した場合にはロールバックするようにした。
データが既に存在する、などの状況はServiceから例外によってControllerに通知するのが楽だし、チェック例外を用いることにより、どういう例外が発生し得るかメソッドのシグネチャで予め知ることが出来るので便利。Controllerではキャッチして適切な処理をする。
その他
起動時のバナーを作ってみたり。
_人人人人人人人人人人人人人人_
> Spring Boot 起動します! <
 ̄Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y ̄
今後
色々さらに拡張していく予定。
WebAppをさくっと作るにはSpring Boot非常に良い。
既にQiita API v2 Hackathonでも利用してその作成スピードは体感済み。
http://eiryu.hatenablog.com/entry/2014/12/21/163531
Spring Boot 1.12から1.2.3に上げたときのメモ
build.gradleのバージョンを上げてbootRunしたら以下のようなエラーが出た。
org.springframework.beans.factory.BeanDefinitionStoreException: Failed to read candidate component class: URL [jar:file:/Users/eiryu/.gradle/caches/modules-2/files-2.1/org.springframework.boot/spring-boot-autoconfigure/1.2.3.RELEASE/11175f217ac34bdacd6282cd44310f211121e270/spring-boot-autoconfigure-1.2.3.RELEASE.jar!/org/springframework/boot/autoconfigure/jdbc/DataSourceAutoConfiguration$JdbcTemplateConfiguration.class]; nested exception is java.lang.IllegalStateException: Could not evaluate condition on org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration$JdbcTemplateConfiguration due to internal class not found. This can happen if you are @ComponentScanning a springframework package (e.g. if you put a @ComponentScan in the default package by mistake)
Applicationクラスがデフォルトパッケージに置いてあるのがダメらしい。任意のパッケージ配下に移動したら解決。
参考
- http://spring.io/guides/gs/rest-service/
- http://is4cafe.hatenablog.com/entry/20140403/1396535920
- http://blog.scheakur.com/post/91500044242/spring-boot-spring-loaded-gradle-intellij
- http://docs.spring.io/spring-boot/docs/current/reference/html/howto-hotswapping.html#howto-reload-springloaded-gradle-and-intellij
- http://dev.classmethod.jp/server-side/java/thymeleaf-spring-i18n-1/
- http://qiita.com/ksby/items/2ea40c5455c31870bd7c
- http://blog.nnasaki.com/entry/spring4/2
- http://docs.spring.io/spring-security/site/docs/current/reference/html/csrf.html