【Spring boot】RestControllerのレスポンスボディにThymeleafで動的に値を埋め込んだhtmlを含める
背景
(タイトルがわかり辛すぎるので背景から...)
Spring bootは@RestController
をつけたクラスのメソッドの返り値がそのままレスポンスボディになります
@RestController public class HelloRestController { @RequestMapping("index") public HelloModel index() { return new HelloModel(200, "Hello, world!"); } }
@Data @AllArgConstructor public class HelloModel { private Integer status; private String message; }
この場合,index
にGETリクエストを送れば下記のようなレスポンスが得られます
{ status: 200, message: "Hello, world!" }
ところで,一般的なwebアプリはhtmlの描画をサーバーサイドでやる同期的な描画と,javascriptで非同期通信をし,取ってきたデータをクライアント側で描画する方法に分けることができるかと思います. ここで,javascript側での描画処理を極力抑えて,ほぼすべての描画をサーバーサイドでやりたいという欲が生まれることがあります.理由は色々ありますが,サーバーサイドで描画を行う方法に統一することで テンプレートがサーバーサイドに集約されて保守がしやすいといったことが挙げられます.
Spring bootのサーバーサイドレンダリングは@Controller
を使います.
@Controller public class HelloController { @RequestMapping("index") public String index(Model model) { model.addAttribute("message","Hello, world!"); return "index"; } }
index.html
<!doctype html> <html xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8" /> <title>Hello World</title> </head> <body> <p th:text="${message}"></p> </body> </html>
ここで,たとえば
{ status: 200, message: "ここにthymeleafで動的に描画したものを埋め込みたい" }
というレスポンスを返したい場合,どのように実装すればいいのかというのをこの記事では紹介します. (調べた限り,Spring Bootの標準的な機能としてこのような使い方が見当たりませんでした.もし標準的な機能で出来る場合はコメントにてご指摘いただけると幸いですmm)
結論
こちらのレポジトリに参考実装を置いてあります. github.com
仕組み
Spring BootにおけるControllerの動き
詳しくはこちら terasolunaorg.github.io
レンダリング処理のポイントは以下の2点です
ViewResolverが描画で使うテンプレートを決定し,Viewインスタンスを返す
ViewがModelを受け取って値を動的に埋め込む
RestControllerでも同じ動きを模倣してあげれば動的に埋め込まれたものを生成することができるので, あとはこれを必要に応じてレスポンスの一部に加えてあげれば良いです.