Table of Contents
「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にパッケージングするときにビルドツールに無視されることが多いため。)
この仕組みについて、この記事を参考にちょろっとソースを見た感じでは、これらのパスはResourceProperties
のCLASSPATH_RESOURCE_LOCATIONS
に定義されていて、これをWebMvcAutoConfiguration
がResourceHandlerRegistry
でリソースロケーションとして登録することで静的リソース置き場たらしめている模様。
(このResourceHandlerRegistry
はResourceHttpRequestHandler
を設定するファサード的なものっぽい。)
で、@SpringBootApplication
(その1参照)が付いているクラスがあって、spring-webmvc.jar
がクラスパスにあると、@EnableWebMvc
がSpring Bootによって付けられ、そこからごにょごにょして上記WebMvcAutoConfiguration
が実行される。
spring-webmvc.jar
はspring-boot-starter-web.jar
(その1参照)が引っ張ってくる。
なお、Spring MVCの静的リソース処理の全体の流れについては
、ちょっと古いけど「handling static web resources」という記事が分かりやすい。
要は、URLに指定されたパスからサーバ上のリソースを探し当てるResourceResolver
というものが優先度順に連なっているリゾルバチェイン(ResourceResolverChain
)があって、まずこいつがリソースを取得する。
次に、そのリソースを加工するトランスフォーマチェイン(ResourceTransformerChain
)というものに通し、その結果をクライアントに返す。
トランスフォーマチェインはResourceTransformer
が連なったもの。
リゾルバチェインとトランスフォーマチェインは上記ResourceHttpRequestHandler
に設定される。
リゾルバには以下の様なものがある。
PathResourceResolver
:ResourceHttpRequestHandler
に設定されたリソースロケーションからリソースを単純に検索するリゾルバ。CachingResourceResolver
: キャッシュからリソースを検索するリゾルバ。テンプレートエンジンの処理結果のキャッシュとかが返るのは多分ここから。GzipResourceResolver
: gzipで圧縮されたリソース、つまりURLで指定されたパスに.gz
という拡張子を付けたリソースを検索するリゾルバ。VersionResourceResolver
: リソースバージョニングを実現するためのリゾルバ。WebJarsResourceResolver
: WebJarsのjarファイル内のリソースを検索するリゾルバ。
リゾルバの設定などについてはQiitaのこの記事ががよくまとまっている。 凝ったことをしたいときは参照しよう。
トランスフォーマには以下の様なものがある。
CssLinkResourceTransformer
: CSSファイル内のリンクをクライアントがアクセスできるURLに変換する。CachingResourceTransformer
: 変換したリソースをキャッシュする。AppCacheManifestTransformer
: HTML5のAppCacheマニフェスト内のリソースを扱うトランスフォーマ。
デフォルトで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.html
とfavicon.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.css
もindex.html
に<link rel="stylesheet" href="goslings.css">
みたいに書けば取得できる。
今日はここまで。 次回からはクライアントサイドの話。
と思ったけど、たいして書くことないのでこれで終わりにする。 Qiitaのほうにちょっと書いたし。