Zrozumienie współdzielonych kroków w konfiguracji projektu jest kluczowe przed zagłębieniem się w szczegóły każdej technologii rozszerzającej klienta. Moje wymagania z ostatniego posta były dość proste:
- Przyjmę punkt widzenia programisty back-end
- Brak etapu kompilacji front-end: brak TypeScript, brak minifikacji itp.
- Wszystkimi zależnościami zarządza się z poziomu aplikacji zaplecza, czyli Maven
Ważne jest, aby zauważyć, że technologia, którą będę szczegółowo opisywał, z wyjątkiem Vaadin, podąża podobnym podejściem. Vaadin, ze swoim unikalnym paradygmatem, naprawdę wyróżnia się wśród podejść.
WebJars to technologia opracowana w 2012 roku przez Jamesa Warda, aby sprostać tym konkretnym wymaganiom.
Pliki WebJars to biblioteki internetowe po stronie klienta (np. jQuery i Bootstrap) spakowane w pliki JAR (Java Archive).
- Jawne i łatwe zarządzanie zależnościami po stronie klienta w aplikacjach internetowych opartych na JVM
- Użyj narzędzi do kompilacji opartych na JVM (np. Maven, Gradle, sbt, ...), aby pobrać zależności po stronie klienta
- Dowiedz się, z jakich zależności po stronie klienta korzystasz
- Zależności przechodnie są automatycznie rozwiązywane i opcjonalnie ładowane za pomocą RequireJS
- Wdrożono w Maven Central
- Publiczna sieć CDN, uprzejmie udostępniona przez JSDelivr
WebJar to zwykły JAR zawierający zasoby sieciowe. Dodanie WebJar do zależności projektu nie jest niczym konkretnym:
<dependencies> <dependency> <groupId>org.webjars.npm</groupId> <artifactId>alpinejs</artifactId> <version>3.14.1</version> </dependency> </dependencies>
Odpowiedzialnością frameworka jest udostępnianie zasobów pod adresem URL. Na przykład Spring Boot robi to w klasie 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/**"
Wewnątrz pliku JAR możesz dotrzeć do zasobów za pomocą ich odpowiedniej ścieżki i nazwy. Uzgodniona struktura polega na przechowywaniu zasobów wewnątrz resources/webjars/<library>/<version>
. Oto struktura pliku 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
W Spring Boot dostęp do wersji niezminifikowanej można uzyskać za pomocą /webjars/alpinejs/3.14.1/dist/cdn.js
.
Programiści dość często udostępniają biblioteki po stronie klienta. Gdy zmieniasz wersję zależności w POM, musisz zmienić ścieżkę front-end, prawdopodobnie w wielu miejscach. To nudne, nie ma żadnej wartości dodanej i ryzykujesz, że przegapisz zmianę.
Projekt WebJars Locator ma na celu uniknięcie wszystkich tych problemów poprzez zapewnienie ścieżki bez wersji, tj . /webjars/alpinejs/dist/cdn.js
. Możesz to osiągnąć, dodając plik JAR webjars-locator
do swoich zależności:
<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>
Będę stosować to podejście do każdej technologii front-end. Dodam również bibliotekę Bootstrap CSS, aby zapewnić lepiej wyglądający interfejs użytkownika.
Thymeleaf to technologia renderowania po stronie serwera.
Thymeleaf to nowoczesny, serwerowy silnik szablonów Java przeznaczony zarówno do środowisk internetowych, jak i autonomicznych.
Głównym celem Thymeleaf jest wprowadzenie eleganckich, naturalnych szablonów do Twojego procesu tworzenia oprogramowania — HTML-a, który można poprawnie wyświetlać w przeglądarkach i który może również pełnić funkcję statycznych prototypów, umożliwiając lepszą współpracę w zespołach programistycznych.
Dzięki modułom dla Spring Framework, licznym integracjom z ulubionymi narzędziami i możliwości podłączania własnych funkcji Thymeleaf idealnie nadaje się do współczesnego tworzenia stron internetowych w formacie HTML5 JVM — choć oferuje znacznie więcej.
Byłem jeszcze konsultantem, kiedy pierwszy raz dowiedziałem się o Thymeleaf. W tamtym czasie Java Server Pages były u schyłku swojego żywota. Java Server Faces próbowało je zastąpić; moim zdaniem, nie udało im się.
Uważałem, że Thymeleaf to fantastyczne podejście: pozwala zobaczyć wyniki w środowisku statycznym w czasie projektowania i w środowisku serwerowym w czasie tworzenia. Co więcej, można płynnie poruszać się między jednym a drugim, używając tego samego pliku. Nigdy nie widziałem, aby ta możliwość była używana.
Jednak Spring Boot w pełni obsługuje Thymeleaf. Wisienka na torcie: ten ostatni jest dostępny za pośrednictwem przestrzeni nazw HTML na stronie. Jeśli nie kupiłeś JSF (spoiler: ja nie), Thymeleaf jest dzisiejszym językiem szablonów SSR.
Oto przykład demonstracyjny ze strony internetowej:
<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>
Oto podstawowe informacje na temat technologii Thymeleaf, na wypadek gdybyś chciał się z nią zapoznać.
Name
i Price
. Gdy używasz go na serwerze, Thymeleaf włącza się i renderuje wartość obliczoną z th:text
, #{msgs.headers.name}
i #{msgs.headers.price}
.$
wysyła zapytanie o obiekt Spring o tej samej nazwie, który został przekazany do modelu. ${prod.name}
jest równoważne z model.getBean("prod").getName()"
.#
wywołuje funkcję.th:each
pozwala na pętle.Większość, jeśli nie wszystkie, frameworki front-endowe działają z modelem po stronie klienta. Musimy połączyć model po stronie serwera i model po stronie klienta.
Kod po stronie serwera, którego używam, jest następujący:
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 ) } } } }
Zdefiniuj klasę Todo
.
Dodaj listę w pamięci do fabryki beanów. W zwykłej aplikacji użyłbyś Repository
do odczytu z bazy danych.
Wyrenderuj szablon HTML.
Szablon to src/main/resources/templates/index.html
i ma atrybuty Thymeleaf.
Umieść model w kontekście strony.
Thymeleaf oferuje atrybut th:inline="javascript"
w tagu <script>
. Renderuje on dane po stronie serwera jako zmienne JavaScript. Dokumentacja wyjaśnia to o wiele lepiej, niż ja kiedykolwiek mógłbym:
Pierwszą rzeczą, jaką możemy zrobić dzięki wstawianiu skryptów, jest wpisywanie wartości wyrażeń do naszych skryptów, na przykład:
<script th:inline="javascript"> /*<![CDATA[*/ ... var username = /*[[${session.user.name}]]*/ 'Sebastian'; ... /*]]>*/ </script>
Składnia
/*[[...]]*/
instruuje Thymeleaf, aby ocenił zawarte wyrażenie. Ale jest tu więcej implikacji:
Ponieważ jest to komentarz JavaScript
(/*...*/)
, nasze wyrażenie zostanie zignorowane podczas statycznego wyświetlania strony w przeglądarce.Kod następujący po wyrażeniu inline (
'Sebastian'
) zostanie wykonany podczas statycznego wyświetlania strony.Thymeleaf wykona wyrażenie i wstawi wynik, ale usunie również cały kod w wierszu następującym po samym wyrażeniu inline (część, która jest wykonywana, gdy jest wyświetlana statycznie).
Jeżeli zastosujemy powyższe wskazówki do naszego kodu, możemy uzyskać atrybuty modelu przekazane przez Springa w następujący sposób:
<script th:inline="javascript"> /*<![CDATA[*/ window.title = /*[[${title}]]*/ 'A Title' window.todos = /*[[${todos}]]*/ [{ 'id': 1, 'label': 'Take out the trash', 'completed': false }] /*]]>*/ </script>
Po wyrenderowaniu po stronie serwera wynik wygląda następująco:
<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>
W tym poście opisałem dwa komponenty, których będę używał przez resztę tej serii:
Pełny kod źródłowy tego wpisu można znaleźć w serwisie GitHub.
Przejdź dalej:
Oryginalnie opublikowano w A Java Geek 15 września 2024 r.