この記事に書いてあること
Tymeleafを使っていて、Javaアプリ側から引き渡した値を使ってHTML側でURLを生成したいような場合があると思います。
例えば、ファイル名は固定だがドメインなどを条件によって切り替えたい場合などです。
簡単な注意点があったのでメモ。
前提
- Spring MVC 5.x
- Java11
- Thymeleaf.3.0.11
先に結論
HTMLにCSSのURLを出す場合は th:href と @{...} を使います。JavaScriptで値が必要なら th:inline="javascript" と [[...]] でJavaScriptの文字列として出力し、URL APIで相対パスを解決します。
実行用サンプル
JDK 17とMaven 3.9系で mvn test を実行します。ZIPにはソース全文・テスト・pom.xml・READMEを収録しています。
assets-example.html の全文
<!doctype html>
<html lang="ja" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>CSSのURL</title>
<link id="local-style" rel="stylesheet" th:href="@{/assets/style.css}">
</head>
<body>
<script th:inline="javascript">
const assetBaseUrl = /*[[${assetBaseUrl}]]*/ "https://static.example.test/css/";
const stylesheetUrl = new URL("style.css", assetBaseUrl).href;
</script>
</body>
</html>MockMvcでCSSの href が /demo/assets/style.css になり、JavaScriptに渡した文字列を解釈すると https://static.example.test/css/ になることを確認しました。これは説明用の固定URLです。
以下の旧例では、HTMLのテンプレートで展開する箇所と、JavaScriptとして実行する箇所を一つの引用符に入れてしまい、+ が演算子として実行されませんでした。
簡単なので以下に例を。Javaのアプリ側からdomainPathという属性で「https://test.domain/path/css/」を引き渡します。
ダメな例(連結に「+」演算子を使用)
var url = '[(${domainPath})] + "style.css"';
上記のようにThymeleafで書くと、HTML上では以下のように出力されました。
var url = 'https://test.domain/path/css/ + "style.css"';
+演算子以降が、URLとは別の文字列として表示されてしまっており、urlという変数にうまく代入されませんでした。
OKな例
var url = '[(${domainPath})]style.css';
上記のようにThymeleafで書くと、HTML上では以下のように出力されました。
var url = 'https://test.domain/path/css/style.css';
+演算子を使わずに記述すると、1つのURL文字列として表現されました。これでJavaScript内でも適切に取り扱うことができるようになりました!
結論だけで終わってしまいました
足し算演算子の有無だけでは、URLが正しく組み立てられるか決まりません。どの文脈で値を解釈させるかを先に決めます。
HTML属性にはURL式を、JavaScriptにはシリアライズした文字列を使います。外部ドメインの基準URLは、利用者の入力をそのまま使わず、信頼できる設定から渡してください。
