各クライアント拡張テクノロジーの詳細を掘り下げる前に、プロジェクト設定の共通手順を理解することが重要です。前回の投稿での私の要件は非常に単純なものでした。
- バックエンド開発者の視点から見てみましょう
- フロントエンドのビルド ステップはありません。TypeScript や縮小などはありません。
- すべての依存関係はバックエンドアプリ、つまりMavenから管理されます。
ここで注目すべきは、私がこれから説明するテクノロジーは、Vaadin を除いて、同様のアプローチを採用しているということです。Vaadin は、そのユニークなパラダイムにより、さまざまなアプローチの中でも際立っています。
WebJars は、まさにこれらの要件に対応するために2012 年に James Ward によって設計されたテクノロジーです。
WebJars は、JAR (Java Archive) ファイルにパッケージ化されたクライアント側の Web ライブラリ (jQuery や Bootstrap など) です。
- JVMベースのWebアプリケーションにおけるクライアント側の依存関係を明示的かつ簡単に管理します。
- JVMベースのビルドツール(Maven、Gradle、sbtなど)を使用してクライアント側の依存関係をダウンロードします。
- 使用しているクライアント側の依存関係を把握する
- 推移的な依存関係は自動的に解決され、オプションでRequireJS経由でロードされます。
- Maven Centralにデプロイ
- JSDelivrが寛大に提供しているパブリック CDN
WebJar は、Web アセットを含む通常の JAR です。プロジェクトの依存関係に WebJar を追加することは特別なことではありません。
<dependencies> <dependency> <groupId>org.webjars.npm</groupId> <artifactId>alpinejs</artifactId> <version>3.14.1</version> </dependency> </dependencies>
フレームワークの役割は、URL の下にあるアセットを公開することです。たとえば、Spring Boot はWebMvcAutoConfiguration
クラスでこれを実行します。
public void addResourceHandlers(ResourceHandlerRegistry registry) { if (!this.resourceProperties.isAddMappings()) { logger.debug("Default resource handling disabled"); return; } addResourceHandler(registry, this.mvcProperties.getWebjarsPathPattern(), //1 "classpath:/META-INF/resources/webjars/"); addResourceHandler(registry, this.mvcProperties.getStaticPathPattern(), (registration) -> { registration.addResourceLocations(this.resourceProperties.getStaticLocations()); if (this.servletContext != null) { ServletContextResource resource = new ServletContextResource(this.servletContext, SERVLET_LOCATION); registration.addResourceLocations(resource); } }); }
"/webjars/**"
です
JAR 内では、それぞれのパスと名前でアセットにアクセスできます。合意された構造は、アセットをresources/webjars/<library>/<version>
内に格納することです。 alpinejs-3.14.1.jar
の構造は次のとおりです。
META-INF |_ MANIFEST.MF |_ maven.org.webjars.npm.alpinejs |_ resources.webjars.alpinejs.3.14.1 |_ builds |_ dist |_ cdn.js |_ cdn.min.js |_ src |_ package.json
Spring Boot 内では、 /webjars/alpinejs/3.14.1/dist/cdn.js
を使用して、縮小されていないバージョンにアクセスできます。
開発者はクライアント側のライブラリを頻繁にリリースします。POM で依存関係のバージョンを変更する場合、フロントエンド パスを複数の場所で変更する必要があります。これは退屈で、付加価値がなく、変更を見逃すリスクがあります。
WebJars Locator プロジェクトは、バージョンなしのパス(例: /webjars/alpinejs/dist/cdn.js
を提供することで、これらすべての問題を回避することを目指しています。これを実現するには、依存関係にwebjars-locator
JAR を追加します。
<dependencies> <dependency> <groupId>org.webjars.npm</groupId> <artifactId>alpinejs</artifactId> <version>3.14.1</version> </dependency> <dependency> <groupId>org.webjars</groupId> <artifactId>webjars-locator</artifactId> <version>0.52</version> </dependency> </dependencies>
このアプローチをすべてのフロントエンド テクノロジに使用します。また、より見栄えの良いユーザー インターフェイスを提供するために、 Bootstrap CSS ライブラリも追加します。
Thymeleaf はサーバー側のレンダリング テクノロジーです。
Thymeleaf は、Web 環境とスタンドアロン環境の両方に対応した最新のサーバー側 Java テンプレート エンジンです。
Thymeleaf の主な目標は、開発ワークフローにエレガントで自然なテンプレート (ブラウザーで正しく表示でき、静的プロトタイプとしても機能する HTML) を導入して、開発チーム内での強力なコラボレーションを可能にすることです。
Spring Framework 用のモジュール、お気に入りのツールとの多数の統合、独自の機能をプラグインする機能などにより、Thymeleaf は現代の HTML5 JVM Web 開発に最適ですが、できることは他にもたくさんあります。
--タイムリーフ
私が初めて Thymeleaf について知ったとき、私はまだコンサルタントでした。当時、Java Server Pages は終焉を迎えようとしていました。Java Server Faces がそれを置き換えようとしていましたが、私の意見では、それは失敗でした。
Thymeleaf は素晴らしいアプローチだと思いました。設計時には静的な環境で結果を確認でき、開発時にはサーバー環境で確認することができます。さらに良いことに、同じファイルを使用して、一方から他方へシームレスに移動することができます。この機能が使用されているのを私は見たことがありません。
ただし、Spring Boot は Thymeleaf を完全にサポートしています。さらに嬉しいことに、後者はページ上の HTML 名前空間を介して利用できます。JSF に賛成していない場合 (ネタバレ: 私は賛成しませんでした)、Thymeleaf は今日の SSR テンプレート言語として最適です。
以下はウェブサイトのデモサンプルです:
<table> <thead> <tr> <th th:text="#{msgs.headers.name}">Name</th> <th th:text="#{msgs.headers.price}">Price</th> </tr> </thead> <tbody> <tr th:each="prod: ${allProducts}"> <td th:text="${prod.name}">Oranges</td> <td th:text="${#numbers.formatDecimal(prod.price, 1, 2)}">0.99</td> </tr> </tbody> </table>
この技術について詳しく知りたい場合は、Thymeleaf 101 をご覧ください。
Name
とPrice
が表示されます。これをサーバーで使用すると、Thymeleaf が起動し、 th:text
、 #{msgs.headers.name}
、 #{msgs.headers.price}
から計算された値がレンダリングされます。$
演算子は、モデルに渡されたのと同じ名前の Spring Bean を照会します。 ${prod.name}
model.getBean("prod").getName()"
と同等です。#
は関数を呼び出します。th:each
ループを許可します。すべてではないにしても、ほとんどのフロントエンド フレームワークはクライアント側モデルで動作します。サーバー側モデルとクライアント側モデルの間に橋渡しをする必要があります。
私が使用しているサーバー側コードは次のとおりです。
data class Todo(val id: Int, var label: String, var completed: Boolean = false) //1 fun config() = beans { bean { mutableListOf( //2 Todo(1, "Go to the groceries", false), Todo(2, "Walk the dog", false), Todo(3, "Take out the trash", false) ) } bean { router { GET("/") { ok().render( //3 "index", //4 mapOf("title" to "My Title", "todos" to ref<List<Todo>>()) //5 ) } } } }
Todo
クラスを定義します。
Bean ファクトリにメモリ内リストを追加します。通常のアプリでは、 Repository
を使用してデータベースから読み取ります。
HTML テンプレートをレンダリングします。
テンプレートは、Thymeleaf 属性を持つsrc/main/resources/templates/index.html
です。
モデルをページのコンテキストに配置します。
Thymeleaf は、 <script>
タグにth:inline="javascript"
属性を提供します。これは、サーバー側のデータを JavaScript 変数としてレンダリングします。ドキュメントには、私が説明するよりもはるかにわかりやすく説明されています。
スクリプトのインライン化で最初にできることは、次のように式の値をスクリプトに書き込むことです。
<script th:inline="javascript"> /*<![CDATA[*/ ... var username = /*[[${session.user.name}]]*/ 'Sebastian'; ... /*]]>*/ </script>
/*[[...]]*/
構文は、Thymeleaf に含まれている式を評価するように指示します。ただし、ここではさらに意味があります。
これは JavaScript コメント
(/*...*/)
であるため、ブラウザーでページを静的に表示するときには、この式は無視されます。インライン式 (
'Sebastian'
) の後のコードは、ページを静的に表示するときに実行されます。Thymeleaf は式を実行して結果を挿入しますが、インライン式自体の後の行 (静的に表示されるときに実行される部分) のすべてのコードも削除します。
上記をコードに適用すると、Spring によって渡されるモデル属性を次のように取得できます。
<script th:inline="javascript"> /*<![CDATA[*/ window.title = /*[[${title}]]*/ 'A Title' window.todos = /*[[${todos}]]*/ [{ 'id': 1, 'label': 'Take out the trash', 'completed': false }] /*]]>*/ </script>
サーバー側でレンダリングすると、結果は次のようになります。
<script> /*<![CDATA[*/ window.title = "My title"; window.todos: [{"id":1,"label":"Go to the groceries","completed":false},{"id":2,"label":"Walk the dog","completed":false},{"id":3,"label":"Take out the trash","completed":false}] /*]]>*/ </script>
この投稿では、このシリーズの残りの部分で使用する 2 つのコンポーネントについて説明しました。
この投稿の完全なソースコードは GitHub にあります。
さらに詳しく:
2024年9月15日にA Java Geekで最初に公開されました