Tue, Jan 24, 2017

Goslings開発メモ - その5: Spring Boot最終編 (静的リソース処理)

Goslings開発メモ - その5: Spring Boot最終編 (静的リソース処理)

Goslings開発メモ - その4: Spring Boot続続続編 (ロギング)」の続き。

Spring Boot最終編で、静的リソース処理について。


Spring Boot(Spring MVC)での静的リソース処理

この時点でのGoslingsは単なるREST APIサーバで、アクセスしてもJSONを返すだけだ。 アプリとしての体を成すためには、そのAPIを利用するクライアントコード、つまりHTMLドキュメントやCSSファイルやJavaScriptファイル(静的リソース)も返すようにしないといけない。 HTMLドキュメントを返す場合、普通はなんらかのテンプレートエンジンを使うものだが、Goslingsは本当に単純なGUIなので、サーバに置いたHTMLファイルをそのまま返したい。

「Getting Started Guides」にはServing Web Content with Spring MVCというのが乗っているが、これはThymeleafというテンプレートエンジンを使うものなのでちょっと違う。


Spring Bootリファレンスガイドによると、クラスパス(またはServletContextのルート)の/static//public//resources//META-INF/resources/のいずれかに静的リソースを置けば、特にコードを書かなくてもクライアントからアクセスできるらしい。 (逆に、一般的に静的リソースを置く場所である、プロジェクトのsrc/main/webapp/には置くべきでないとのこと。これは、jarにパッケージングするときにビルドツールに無視されることが多いため。)

この仕組みについて、この記事を参考にちょろっとソースを見た感じでは、これらのパスはResourcePropertiesCLASSPATH_RESOURCE_LOCATIONSに定義されていて、これをWebMvcAutoConfigurationResourceHandlerRegistryリソースロケーションとして登録することで静的リソース置き場たらしめている模様。 (このResourceHandlerRegistryResourceHttpRequestHandlerを設定するファサード的なものっぽい。)

で、@SpringBootApplication(その1参照)が付いているクラスがあって、spring-webmvc.jarがクラスパスにあると、@EnableWebMvcがSpring Bootによって付けられ、そこからごにょごにょして上記WebMvcAutoConfigurationが実行される。 spring-webmvc.jarspring-boot-starter-web.jar(その1参照)が引っ張ってくる。


なお、Spring MVCの静的リソース処理の全体の流れについては 、ちょっと古いけど「handling static web resources」という記事が分かりやすい。 要は、URLに指定されたパスからサーバ上のリソースを探し当てるResourceResolverというものが優先度順に連なっているリゾルバチェイン(ResourceResolverChain)があって、まずこいつがリソースを取得する。 次に、そのリソースを加工するトランスフォーマチェイン(ResourceTransformerChain)というものに通し、その結果をクライアントに返す。 トランスフォーマチェインはResourceTransformerが連なったもの。 リゾルバチェインとトランスフォーマチェインは上記ResourceHttpRequestHandlerに設定される。

リゾルバには以下の様なものがある。

リゾルバの設定などについてはQiitaのこの記事ががよくまとまっている。 凝ったことをしたいときは参照しよう。


トランスフォーマには以下の様なものがある。


デフォルトでResourceHttpRequestHandlerにはPathResourceResolverだけが設定されている。


以上をまとめると、クライアントからGetリクエストが来ると、WebMvcAutoConfigurationが設定したリソースロケーション(e.g. /static/)をPathResourceResolverが検索して、そこに置いてあるHTMLファイルとかをクライアントに返してくれる、ということであろう。

Javaのコードを全く書かなくていいので楽。


Javaのコードを書いて静的リソースファイルを明示することもできる。 Qiitaの記事によれば、@Controllerを付けたクラスのリクエストハンドラで以下の様にファイルへのパスを返せばいいらしい。

@RequestMapping("/hoge")
public String hoge() {
    return "/hoge.html";
}

単純な静的リソースに対してこれをやるユースケースはあまりなさそう。 テンプレートエンジンを使っていてパラメータを渡したいときにはこういうリクエストハンドラを書くことになる。

Spring Bootのウェルカムページとファビコン

Spring Bootはindex.htmlfavicon.icoという名のファイルを特別扱いする。 前者がウェルカムページで後者がファビコン。

ウェルカムページ

Spring Bootのリファレンスガイドにもちらっとかいてあるけど、リソースロケーションにindex.htmlというファイルを置いておくと、それがウェルカムページとして設定され、URLのパスにルート(e.g. http://localhost:8080/)を指定したときにクライアントに返るようになる。

ソースを見ると、上記WebMvcAutoConfigurationここでそのための設定している。 /META-INF/resources/index.html/resources/index.html/static/index.html/public/index.htmlの順に探すようで、複数個所にindex.htmlを置いた場合は最初に見つかったものがウェルカムページになる。(そんなことする意味はないが。)

ファビコン

ファビコンについてはSpring Bootの現時点でリリース済みバージョンのリファレンスガイドにはほとんど情報がないが、1.5.0.BUILD-SNAPSHOTのリファレンスガイドには以下の様に書いてある。

27.1.6 Custom Favicon

Spring Boot looks for a favicon.ico in the configured static content locations and the root of > the classpath (in that order). If such file is present, it is automatically used as the favicon > of the application.

つまり、リソースロケーションかクラスパスのルートにfavicon.icoというファイルを置いておくと、それをファビコンとしてクライアントに返してくれる。

これもやっぱりWebMvcAutoConfiguration設定する

Goslingsの静的リソース

Goslingsの静的リソースはfavicon.ico以外は/static/に全部直接置くことにした。 favicon.icoはクラスパスのルートに。 プロジェクトのソースツリーで言うと、src/main/resources/static/index.htmlやらgoslings.cssやらのクライアントファイルを置いて、あとはsrc/main/resources/favicon.icoがあるという形。 こうしておけば、GradleのJavaプラグインのprocessResourcesタスクによってjar内の適切な場所に取り込まれる。

index.htmlにはhttp://<Goslingsサーバ>/でアクセスできるし、goslings.cssindex.html<link rel="stylesheet" href="goslings.css">みたいに書けば取得できる。


今日はここまで。 次回からはクライアントサイドの話。