アイキャッチ

実装・エラー解決

SpringBootで画面ファイルを外だしするには

このページに書いてあること。

JavaFrameWorkのSpringBootで画面ファイルを好きなフォルダに配置してアプリケーションの戻り値として使用するにはどうすればいいのか調べたのでリマインダとしてメモ

  • @Controllerを適用したクラスで、画面ファイルを外だしする
  • その画面を戻り値として返す

背景:

1)通常、ThymeleafのHTMLテンプレートを src/main/resources/templates に置きます。

2)war化してアプリケーションを配備した場合、templatesはwarの中に込められてしまい、warからデプロイするような環境では画面の変更にリビルドが必要になってしまう。

※warから展開したwebapps以下やwork以下を直接弄る場合は問題ないが、再デプロイ時に消し飛ぶ可能性があり、嫌がられた

3)どうやったら設定ファイルと同様に外部化できるのだろうか。

というもの。

結論:

実行用サンプル

外部テンプレートを優先し、外したときにjarに同梱したHTMLへ戻ることを確かめます。 検証コードを見る。 JDK 17とMaven 3.9系で試せます。ソース・テスト・pom.xml・READMEをZIPに収録しています。

Spring BootとThymeleafの現在の例では、外部ディレクトリを読む FileTemplateResolver を加えます。旧外部Tomcatでクラスパスを調整した経緯とは分けて考えます。

ExternalTemplateConfiguration.java の全文

package info.syachiku.maintenance;

import java.nio.file.Path;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.thymeleaf.templatemode.TemplateMode;
import org.thymeleaf.templateresolver.FileTemplateResolver;

@Configuration(proxyBeanMethods = false)
class ExternalTemplateConfiguration {
    @Bean
    FileTemplateResolver externalTemplateResolver(
            @Value("${demo.templates-directory:external-templates}") Path directory) {
        var resolver = new FileTemplateResolver();
        resolver.setPrefix(directory.toAbsolutePath().normalize() + "/");
        resolver.setSuffix(".html");
        resolver.setTemplateMode(TemplateMode.HTML);
        resolver.setCharacterEncoding("UTF-8");
        resolver.setOrder(1);
        resolver.setCheckExistence(true);
        resolver.setCacheable(false);
        return resolver;
    }
}

ViewController.java の全文

package info.syachiku.maintenance;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
class ViewController {
    @GetMapping("/external-view")
    String external() {
        return "home";
    }

    @GetMapping("/missing-view")
    String missing() {
        return "not-present";
    }

    @GetMapping("/body")
    @ResponseBody
    String body() {
        return "home";
    }
}

上の設定は外部ディレクトリを先に探し、なければ同梱のテンプレートへ進みます。

Controllerはファイル名ではなくビュー名 home を返します。Resolverのsuffixが .html なので、探索対象は home.html になります。

Bootの標準Resolverは classpath:/templates/ を探します。外部Resolverで存在確認を有効にすると、外部ファイルの欠落時に同梱版へフォールバックできます。

配布例では demo.templates-directory に外部ディレクトリを指定します。

JDK 17・Spring Boot 3.5.16で、外部の home.html を置いた場合と外した場合をMockMvcで比較しています。外部Tomcatでのクラスパス追加は今回のサンプルとは別です。

他に試したこと:

1)ResourceHandlerを使ってファイルを読み込んで、メソッド引数に指定したHttpResponseServletに直接書き込む。

2)@ResponseBodyをつかって、FileReaderを使って読み込んだファイル内容を直接コンテンツを返す。

どちらも実現はできるのですが、ハンドリングが非常に面倒。

TemplatesResolver使うのが一番いいですね。

-実装・エラー解決
-,