Thymeleaf javascript 変数操作の便利な書き方
新人
「先輩、ThymeleafでControllerから渡した値をJavaScriptの中で使う方法ってあるんですか?」
先輩
「もちろんあるよ。Thymeleafにはth:inline="javascript"という便利な仕組みがあって、サーバー側の値を安全にJavaScriptに埋め込めるんだ。」
新人
「へぇ〜、サーバーの値をそのままスクリプトで使えるんですね!実際にはどんな書き方をするんですか?」
先輩
「じゃあ、ThymeleafとJavaScriptの連携の基本から順に見ていこうか。」
1. ThymeleafとJavaScriptの基本連携とは?
Thymeleaf(タイムリーフ)はSpring BootやSpring MVCでよく使われるテンプレートエンジンです。サーバーサイドのJavaコードで生成した値をHTMLに動的に埋め込むことができるのが特徴です。これを活かすと、サーバーで用意したデータをJavaScriptに渡して、動的な画面制御を行うことが可能になります。
通常、JavaScriptではクライアントサイドでのみデータを扱いますが、Thymeleafを使えばControllerのModelに格納された値をテンプレートを通じてスクリプトに受け渡せます。つまり、フロントとサーバーをシームレスに連携させられるというわけです。
例えば、ログイン中のユーザー名や設定値などをサーバーで保持し、それをJavaScriptで使うことで動的なUIを実現できます。Thymeleafを使うとHTMLとJavaScriptの両方を一元的に管理できるため、保守性も高まります。
この連携を支えているのが、th:inline="javascript"属性です。これを使うと、Thymeleafの変数展開構文[[${変数}]]をスクリプト内で使えるようになります。
2. ControllerからJavaScriptへ変数を渡す基本構造
まずは、Springの@ControllerからThymeleafへデータを渡す基本の仕組みを確認しておきましょう。SpringではModelオブジェクトを介してテンプレートに値を渡します。pleiades環境でGradleプロジェクトを作成した場合も同じ構成です。
以下は、Controllerからユーザー名と年齢を渡すサンプルです。
@Controller
public class UserController {
@GetMapping("/user")
public String showUser(Model model) {
model.addAttribute("userName", "太郎");
model.addAttribute("userAge", 28);
return "user";
}
}
このようにして、Controllerで設定したデータはModelを通じてuser.htmlテンプレートに渡されます。
そしてThymeleafテンプレートでは、そのデータをJavaScript内に埋め込むことができます。次にその書き方を見てみましょう。
3. th:inline="javascript" の使い方と注意点
th:inline="javascript"は、Thymeleafでサーバー側の値をスクリプト内に直接埋め込むための仕組みです。この属性をscriptタグに指定することで、変数展開構文[[${...}]]をJavaScriptコードの中でも使えるようになります。
次のサンプルを見てください。
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Thymeleaf JavaScript 連携サンプル</title>
</head>
<body>
<h3>ThymeleafからJavaScriptへ変数を渡す</h3>
<script th:inline="javascript">
/*<![CDATA[*/
let name = [[${userName}]];
let age = [[${userAge}]];
alert("ユーザー名:" + name + "(年齢:" + age + ")");
/*]]>*/
</script>
</body>
</html>
ここでは、Controllerで設定したuserNameとuserAgeをJavaScript変数に埋め込んでいます。ページを開くと、アラートで「ユーザー名:太郎(年齢:28)」と表示されます。
ただし、注意すべき点もあります。Thymeleafでは、文字列と数値の扱い方が異なるため、文字列の場合はクォート(ダブルクォーテーション)で囲む必要があります。例えば、次のように記述すると安全です。
<script th:inline="javascript">
/*<![CDATA[*/
let name = [[${userName} == null ? "'未設定'" : "'" + ${userName} + "'"]];
let age = [[${userAge}]];
console.log("名前:" + name + " 年齢:" + age);
/*]]>*/
</script>
このように三項演算子を使えば、値がnullの場合の処理も行えます。Thymeleafではスクリプト内のエスケープ処理が自動で行われるため、HTMLやJavaScriptの構文エラーを防ぎつつ安全にデータを埋め込めます。
特に初心者がつまずきやすいのは、クォートを忘れて文字列が正しく扱えないケースです。例えば、サーバー側で「太郎」という文字列を渡しても、クォートを付けずにlet name = [[${userName}]];と書くと、JavaScript的には未定義変数扱いになってしまいます。
ThymeleafでJavaScriptを扱うときは、数値はそのまま、文字列は必ずクォートで囲むというルールを覚えておきましょう。
次回は、実際に配列やオブジェクトをControllerから渡して、JavaScriptで操作する方法を詳しく解説していきます。
4. JavaScriptで受け取った変数を使う例(動的メッセージ表示など)
ここからは、Thymeleafで渡された変数をJavaScriptの中で実際に使う方法を見ていきましょう。サーバー側のControllerから送られた値を使って、動的にメッセージを切り替えたり、ボタンの表示を変えたりすることができます。初心者がつまずきやすいポイントでもあるので、順を追って理解していきましょう。
まず、@Controller側でメッセージを渡します。
@Controller
public class MessageController {
@GetMapping("/message")
public String showMessage(Model model) {
model.addAttribute("userName", "花子");
model.addAttribute("loginTime", "午前9時");
return "message";
}
}
次に、Thymeleafのテンプレートでその値をth:inline="javascript"を使って受け取ります。
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Thymeleaf JavaScript 変数操作</title>
</head>
<body>
<h3>ログインメッセージ表示サンプル</h3>
<div id="messageArea"></div>
<script th:inline="javascript">
/*<![CDATA[*/
let name = [[${userName} == null ? "'ゲスト'" : "'" + ${userName} + "'"]];
let time = [[${loginTime} == null ? "'不明'" : "'" + ${loginTime} + "'"]];
document.getElementById("messageArea").innerText = name + "さん、ログイン時間は " + time + " です。";
/*]]>*/
</script>
</body>
</html>
このようにすることで、Controllerで指定したuserNameとloginTimeの値がページに動的に表示されます。もし値がnullの場合でも、代替メッセージを出すようにしておくと、初心者にも扱いやすい堅牢なコードになります。
この仕組みを応用すると、ログイン状態に応じてボタンを非表示にしたり、画面上のメニューを切り替えたりすることもできます。
5. Booleanや数値など異なる型の扱い方
ThymeleafからJavaScriptに変数を渡すとき、型の扱いには注意が必要です。特にBoolean(真偽値)や数値は、文字列とは異なりクォートで囲まずに渡します。間違えると条件分岐が正しく動かなくなってしまうため、初心者はここを意識しておきましょう。
まずは@Controller側の設定です。
@Controller
public class FlagController {
@GetMapping("/flag")
public String showFlag(Model model) {
model.addAttribute("isAdmin", true);
model.addAttribute("score", 85);
return "flag";
}
}
次に、ThymeleafでそれをJavaScriptに埋め込みます。
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Booleanと数値の扱い</title>
</head>
<body>
<h3>ユーザー権限とスコア表示</h3>
<div id="result"></div>
<script th:inline="javascript">
/*<![CDATA[*/
let admin = [[${isAdmin}]];
let score = [[${score}]];
if (admin) {
document.getElementById("result").innerText = "管理者モードでログインしています。スコア:" + score;
} else {
document.getElementById("result").innerText = "一般ユーザーとしてログインしています。スコア:" + score;
}
/*]]>*/
</script>
</body>
</html>
ここで注目すべきは、admin変数にはクォートが付いていない点です。Boolean値や数値をクォートで囲んでしまうと、JavaScriptでは文字列として扱われてしまい、条件分岐がうまく動作しなくなります。
このように、Thymeleafでは型に応じてクォートの有無を使い分けるのがポイントです。
6. 配列・Map・オブジェクトをThymeleafからJavaScriptに渡す実践例
最後に、少し応用的な例として配列やMap(キーと値のセット)を渡す方法を紹介します。これが理解できれば、画面上のリスト表示や複雑なデータ構造も自在に扱えるようになります。
まず、Controllerでリストとマップを設定します。
@Controller
public class DataController {
@GetMapping("/data")
public String showData(Model model) {
List<String> fruits = List.of("りんご", "みかん", "ぶどう");
Map<String, Integer> stock = Map.of("りんご", 5, "みかん", 3, "ぶどう", 10);
model.addAttribute("fruits", fruits);
model.addAttribute("stock", stock);
return "data";
}
}
続いて、Thymeleafテンプレート側で受け取り、JavaScriptで操作してみます。
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Thymeleaf 配列とMapの受け渡し</title>
</head>
<body>
<h3>在庫一覧表示サンプル</h3>
<ul id="listArea"></ul>
<script th:inline="javascript">
/*<![CDATA[*/
let fruits = [[${fruits}]];
let stock = [[${stock}]];
let listHtml = "";
for (let i = 0; i < fruits.length; i++) {
let item = fruits[i];
listHtml += "<li>" + item + ":在庫 " + stock[item] + " 個</li>";
}
document.getElementById("listArea").innerHTML = listHtml;
/*]]>*/
</script>
</body>
</html>
この例では、Controllerで渡した配列とMapをJavaScript側で受け取り、ループ処理を使ってHTMLのリストとして描画しています。Thymeleafが自動でJSON形式に変換してくれるため、JavaScript側ではそのままオブジェクトとして扱えます。
この方法を応用すれば、ユーザー一覧や商品リストなどを動的に生成することも可能になります。JavaScriptとThymeleafの連携をマスターすれば、サーバーのデータを効率よくフロントエンドに反映できるようになります。
次回は、これらのデータを使ってボタン制御や非同期通信と組み合わせる実践的なテクニックを紹介していきましょう。
7. JSON形式のデータを扱う方法(MapやDTOをJavaScriptで受け取る)
ここでは、ThymeleafでModelに渡された複雑なデータ構造、つまりJSON形式のデータをJavaScriptで扱う方法を解説します。MapやDTO(データ転送オブジェクト)をJavaScriptで扱うケースは、実務でも非常によく登場します。
まず、ControllerでDTOオブジェクトを作成し、Thymeleafへ渡す例を見てみましょう。
public class UserDto {
private String name;
private int age;
private String email;
// ゲッターとセッターを省略
}
次に、ControllerでこのDTOをModelに追加します。
@Controller
public class JsonController {
@GetMapping("/json")
public String showJson(Model model) {
UserDto user = new UserDto();
user.setName("佐藤");
user.setAge(25);
user.setEmail("sato@example.com");
model.addAttribute("userData", user);
return "json";
}
}
Thymeleafテンプレート側では、th:inline="javascript"を使用してオブジェクト全体をJavaScript変数として受け取ります。
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Thymeleaf JSONデータ受け取り</title>
</head>
<body>
<h3>DTOをJavaScriptで扱うサンプル</h3>
<div id="userInfo"></div>
<script th:inline="javascript">
/*<![CDATA[*/
let user = [[${userData}]];
document.getElementById("userInfo").innerText =
"名前:" + user.name + " 年齢:" + user.age + " メール:" + user.email;
/*]]>*/
</script>
</body>
</html>
Thymeleafは、JavaのオブジェクトをJSON形式に自動変換して埋め込んでくれるため、JavaScript側ではまるで最初からJSONを受け取ったかのように扱うことができます。この仕組みを理解しておくと、複数の項目をまとめて渡したい場合や、REST API連携の前段階でも役立ちます。
また、Thymeleafでは自動的にHTMLエスケープ処理が行われるため、XSS(クロスサイトスクリプティング)攻撃のリスクを軽減できます。特にユーザー入力を扱う場合は、この安全機構を意識しておくことが重要です。
8. 条件分岐・イベント制御でThymeleaf変数を活用する方法
次に、JavaScriptのイベント制御とThymeleafの変数を組み合わせて動的な画面制御を行う方法を見ていきましょう。例えば、Controllerから渡されたステータス値に応じてボタンの表示・非表示を切り替えるといった処理です。
まずはController側で状態を渡します。
@Controller
public class StatusController {
@GetMapping("/status")
public String showStatus(Model model) {
model.addAttribute("isActive", true);
model.addAttribute("userName", "高橋");
return "status";
}
}
続いて、Thymeleafテンプレートで条件分岐とクリックイベントを実装します。
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Thymeleaf 条件分岐とイベント制御</title>
</head>
<body>
<h3>ユーザー状態によるボタン制御</h3>
<button id="actionBtn">操作ボタン</button>
<script th:inline="javascript">
/*<![CDATA[*/
let active = [[${isActive}]];
let name = [[${userName} == null ? "'ゲスト'" : "'" + ${userName} + "'"]];
let btn = document.getElementById("actionBtn");
if (!active) {
btn.style.display = "none";
alert(name + "さんは現在操作できません。");
} else {
btn.addEventListener("click", function() {
alert(name + "さんが操作を実行しました。");
});
}
/*]]>*/
</script>
</body>
</html>
この例では、Controllerから渡されたisActiveがfalseならボタンを非表示にし、trueならクリックイベントを有効にしています。これにより、サーバー側の状態をもとにクライアントの操作を制御することができます。
Thymeleaf JavaScript 連携の利点は、サーバーとフロントエンドを同じテンプレート内で安全に制御できる点にあります。Spring MVCのControllerで定義した状態を画面に反映できるのは大きな強みです。
9. 実務で役立つThymeleafとJavaScript連携のベストプラクティス
ここまでで、ThymeleafとJavaScriptを連携させて変数渡しを行う基本から応用までを学びました。最後に、実務で活用する際のベストプラクティスをいくつか紹介します。
① 文字列と数値のクォートを正しく使い分ける
ThymeleafでJavaScriptに変数を埋め込む際は、文字列をクォートで囲むことを忘れないようにしましょう。数値やBooleanはクォート不要です。このルールを守らないと、型の不一致によるエラーが起きやすくなります。
② null対策を徹底する
サーバー側から渡されるデータがnullの場合、JavaScriptで未定義エラーになることがあります。[[${変数} == null ? "'未設定'" : "'" + ${変数} + "'"]]のように、三項演算子で安全にフォールバック値を指定しておきましょう。
③ XSS対策を意識する
Thymeleafでは自動でエスケープ処理が行われますが、もしth:utextを使って生のHTMLを出力する場合は特に注意が必要です。ユーザー入力を直接JavaScriptに渡すときは、サーバー側でのサニタイズ(危険文字の除去)を忘れずに行いましょう。
④ th:inline="javascript" は必要な箇所だけに使う
テンプレート全体でth:inline="javascript"を乱用すると、可読性が低下しやすくなります。変数渡しが必要なスクリプトだけに限定して使うことで、保守性を保ちつつ安全な設計ができます。
⑤ データ構造を整理して渡す
Controllerで渡すデータは、できるだけDTOやMapにまとめるのが実務的です。個別の値をバラバラに渡すよりも、ひとつのオブジェクトとして扱った方が拡張性が高く、フロント側でも管理しやすくなります。
⑥ JavaScript内ではconstやletを適切に使う
Thymeleafから受け取った値をJavaScriptで再代入しない場合はconstを使いましょう。これにより予期せぬ再代入ミスを防ぎ、コードの安全性が高まります。
このようなポイントを意識することで、ThymeleafとJavaScriptの連携をより安全かつ効果的に行うことができます。Spring MVCのControllerで整えたデータをフロント側で正しく活用すれば、複雑な動的画面もシンプルな構成で実現できます。
次の記事では、Thymeleafで非同期通信(Ajax)と組み合わせることで、よりリアルタイムな画面更新を行う方法を紹介していきます。