{"id":27902,"date":"2024-06-05T05:00:00","date_gmt":"2024-06-05T03:00:00","guid":{"rendered":"https:\/\/sii.pl\/blog\/?p=27902"},"modified":"2024-07-22T14:05:42","modified_gmt":"2024-07-22T12:05:42","slug":"hilla-optymalna-integracja-technologii-czyli-spring-boot-i-react-w-jednym-miejscu","status":"publish","type":"post","link":"https:\/\/sii.pl\/blog\/hilla-optymalna-integracja-technologii-czyli-spring-boot-i-react-w-jednym-miejscu\/","title":{"rendered":"Hilla: optymalna integracja technologii, czyli Spring Boot i React w jednym miejscu"},"content":{"rendered":"\n<p>W \u015bwiecie rozproszonych system\u00f3w webowych, utrzymanie r\u00f3wnowagi mi\u0119dzy backendem a frontendem cz\u0119sto jest wyzwaniem, kt\u00f3remu nie\u0142atwo sprosta\u0107. Pracuj\u0105c z oddzielnymi warstwami, programi\u015bci napotykaj\u0105 problemy zwi\u0105zane z synchronizacj\u0105, komunikacj\u0105 i skalowalno\u015bci\u0105. Na szcz\u0119\u015bcie, na horyzoncie pojawia si\u0119 wyj\u0105tkowe rozwi\u0105zanie \u2013 Hilla. <\/p>\n\n\n\n<p>W tym artykule odkryjemy, jak Hilla u\u0142atwia p\u0142ynn\u0105 komunikacj\u0119 mi\u0119dzy warstw\u0105 backendu a warstw\u0105 frontendu, gwarantuj\u0105c jednocze\u015bnie efektywno\u015b\u0107. Nast\u0119pnie skoncentrujemy si\u0119 na walidacji formularzy, prezentuj\u0105c, jak Hilla sprawia, \u017ce proces ten staje si\u0119 prostszy, bezpieczniejszy i bardziej efektywny.<\/p>\n\n\n\n<figure class=\"wp-block-image aligncenter size-full\"><a href=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/05\/image1-4.png\"><img decoding=\"async\" width=\"300\" height=\"110\" src=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/05\/image1-4.png\" alt=\"hilla\" class=\"wp-image-27903\"\/><\/a><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Czym jest Hilla?<\/strong><\/h2>\n\n\n\n<p>Hilla to innowacyjny framework stworzony przez zesp\u00f3\u0142 Vaadin. \u0141\u0105czy w sobie narz\u0119dzie Spring Boot oraz bibliotek\u0119 React. Oferuje nie tylko skuteczn\u0105 i \u0142atw\u0105 integracj\u0119, ale rozwi\u0105zuje r\u00f3wnie\u017c problemy z utrzymywaniem oddzielnych warstw backendu i frontendu. Zapewnia wygod\u0119 i efektywno\u015b\u0107 w procesie tworzenia aplikacji webowych.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Struktura projektu w Hilla<\/strong><\/h2>\n\n\n\n<p>Warunkiem rozpocz\u0119cia pracy z Hilla jest zainstalowanie na komputerze NodeJS oraz interfejsu wiersza polece\u0144 npm (npx jest ju\u017c zainstalowany w npm od wersji 5.2.0).<\/p>\n\n\n\n<p>Aby zacz\u0105\u0107 prac\u0119 z Hilla, konieczne jest utworzenie projektu. Poni\u017cej znajduje si\u0119 komenda, kt\u00f3ra to umo\u017cliwi:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">npx @hilla\/cli init hilla-blog<\/pre>\n\n\n\n<p>Oto jak wygl\u0105da struktura katalog\u00f3w po wygenerowaniu projektu:<\/p>\n\n\n\n<figure class=\"wp-block-image aligncenter size-full\"><a href=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/05\/image2-4.png\"><img decoding=\"async\" width=\"418\" height=\"742\" src=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/05\/image2-4.png\" alt=\"struktura projektu\" class=\"wp-image-27905\" srcset=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/05\/image2-4.png 418w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/05\/image2-4-169x300.png 169w\" sizes=\"(max-width: 418px) 100vw, 418px\" \/><\/a><\/figure>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Frontend (React)\n<ul class=\"wp-block-list\">\n<li><strong>frontend\/components <\/strong>\u2013katalog zawieraj\u0105cy komponenty React, kt\u00f3re s\u0105 budulcem interfejsu u\u017cytkownika. Tutaj zawarte s\u0105 elementy wizualne i funkcjonalne, takie jak przyciski, formularze czy karty.<\/li>\n\n\n\n<li><strong>frontend\/themes <\/strong>\u2013katalog dedykowany stylom i motywom graficznym. Zawiera pliki dotycz\u0105ce arkuszy styl\u00f3w, ustawie\u0144 kolor\u00f3w czy czcionek, umo\u017cliwiaj\u0105c \u0142atwe zarz\u0105dzanie wygl\u0105dem aplikacji.<\/li>\n\n\n\n<li><strong>frontend\/util <\/strong>\u2013katalog z narz\u0119dziami i funkcjami pomocniczymi, kt\u00f3re mog\u0105 by\u0107 u\u017cywane w r\u00f3\u017cnych miejscach projektu. Zawiera funkcje og\u00f3lnego przeznaczenia, kt\u00f3re u\u0142atwiaj\u0105 manipulacj\u0119 danymi czy wykonywanie pewnych operacji.<\/li>\n\n\n\n<li><strong>frontend\/views <\/strong>\u2013katalog z widokami, czyli g\u0142\u00f3wnymi strukturami stron w aplikacji. Tutaj umieszczane s\u0105 pliki odpowiedzialne za renderowanie konkretnych sekcji interfejsu u\u017cytkownika.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li>Backend (Spring Boot)\n<ul class=\"wp-block-list\">\n<li><strong>src\/main\/java\/com\/example\/application <\/strong>\u2013klasyczna struktura plik\u00f3w w projekcie Spring Boot.<\/li>\n<\/ul>\n<\/li>\n<\/ol>\n\n\n\n<p>Ta struktura projektu u\u0142atwia nawigacj\u0119 oraz r\u00f3wnie\u017c organizuje kod w spos\u00f3b, kt\u00f3ry wspiera rozw\u00f3j zar\u00f3wno frontendu, jak i backendu. Dzi\u0119ki oddzieleniu katalog\u00f3w &#8222;frontend&#8221; i &#8222;src,&#8221; Hilla umo\u017cliwia skoncentrowanie si\u0119 na efektywnej pracy nad obiema warstwami aplikacji.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Jak dzia\u0142a Hilla?<\/strong><\/h2>\n\n\n\n<p>Hilla umo\u017cliwia wywo\u0142ywanie metod Java z poziomu TypeScript. Kluczowym elementem tej funkcjonalno\u015bci jest adnotacja @BrowserCallable. Wszystkie metody publiczne w klasie, oznaczonej t\u0105 adnotacj\u0105, staj\u0105 si\u0119 dost\u0119pne i wywo\u0142ywalne po stronie frontendu. Podczas uruchamiania projektu Hilla wygeneruje w TypeScript odpowiedniki struktur danych u\u017cytych w klasie oznaczon\u0105 adnotacj\u0105 @BrowserCallable. Dodatkowo, tworzy odpowiednik tej klasy, umo\u017cliwiaj\u0105c p\u0142ynne i bezproblemowe korzystanie z tych metod po stronie frontendowej.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Demonstracja dzia\u0142ania Hilla na przyk\u0142adzie projektu<\/strong><\/h2>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Warstwa backend<\/strong><\/h3>\n\n\n\n<p>Na potrzeby tego artyku\u0142u przygotuj\u0119 warstw\u0119 backendow\u0105 sk\u0142adaj\u0105c\u0105 si\u0119 z encji, repozytorium, dto, mappera i serwisu w celu pokazania dzia\u0142ania frameworka Hilla.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Encja:<\/li>\n<\/ul>\n\n\n\n<figure class=\"wp-block-image aligncenter size-full\"><a href=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/05\/image3-4.png\"><img decoding=\"async\" width=\"593\" height=\"873\" src=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/05\/image3-4.png\" alt=\"encja\" class=\"wp-image-27907\" srcset=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/05\/image3-4.png 593w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/05\/image3-4-204x300.png 204w\" sizes=\"(max-width: 593px) 100vw, 593px\" \/><\/a><\/figure>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Repozytorium:<\/li>\n<\/ul>\n\n\n\n<figure class=\"wp-block-image aligncenter size-full\"><a href=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/05\/image4-3.png\"><img decoding=\"async\" width=\"647\" height=\"289\" src=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/05\/image4-3.png\" alt=\"repozytorium\" class=\"wp-image-27909\" srcset=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/05\/image4-3.png 647w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/05\/image4-3-300x134.png 300w\" sizes=\"(max-width: 647px) 100vw, 647px\" \/><\/a><\/figure>\n\n\n\n<ul class=\"wp-block-list\">\n<li>DTO:<\/li>\n<\/ul>\n\n\n\n<figure class=\"wp-block-image aligncenter size-full\"><a href=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/05\/image5-3.png\"><img decoding=\"async\" width=\"312\" height=\"277\" src=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/05\/image5-3.png\" alt=\"DTO\" class=\"wp-image-27911\" srcset=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/05\/image5-3.png 312w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/05\/image5-3-300x266.png 300w\" sizes=\"(max-width: 312px) 100vw, 312px\" \/><\/a><\/figure>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Mapper (wykorzystam narz\u0119dzie MapStruct):<\/li>\n<\/ul>\n\n\n\n<figure class=\"wp-block-image aligncenter size-full\"><a href=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/05\/image6-2.png\"><img decoding=\"async\" width=\"525\" height=\"368\" src=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/05\/image6-2.png\" alt=\"mapper\" class=\"wp-image-27913\" style=\"object-fit:cover\" srcset=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/05\/image6-2.png 525w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/05\/image6-2-300x210.png 300w\" sizes=\"(max-width: 525px) 100vw, 525px\" \/><\/a><\/figure>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Serwis:<\/li>\n<\/ul>\n\n\n\n<figure class=\"wp-block-image aligncenter size-full\"><a href=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/05\/image7-2.png\"><img decoding=\"async\" width=\"666\" height=\"839\" src=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/05\/image7-2.png\" alt=\"serwis\" class=\"wp-image-27915\" srcset=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/05\/image7-2.png 666w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/05\/image7-2-238x300.png 238w\" sizes=\"(max-width: 666px) 100vw, 666px\" \/><\/a><\/figure>\n\n\n\n<p>Doda\u0142em do serwisu dwie metody:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>findAll() \u2013 kt\u00f3ra pos\u0142u\u017cy do wyszukania wszystkich rekord\u00f3w Car,<\/li>\n\n\n\n<li>create(CarDTO carDTO) \u2013 kt\u00f3ra pos\u0142u\u017cy do stworzenia nowego rekordu Car.<\/li>\n<\/ul>\n\n\n\n<p>W serwisie u\u017cy\u0142em metody @BrowserCallable, aby umo\u017cliwi\u0107 wywo\u0142ywanie metod z aplikacji React. Dodatkowo u\u017cy\u0142em adnotacji @AnonymousAllowed, aby wy\u0142\u0105czy\u0107 kontrol\u0119 dost\u0119pu, kt\u00f3r\u0105 zapewnia Hilla (<strong>nie zalecam<\/strong> robienia tego w aplikacji \u2013 robi\u0119 to tylko na potrzeby tego artyku\u0142u).<\/p>\n\n\n\n<p>Typy non-nullable s\u0105 obowi\u0105zkowe, wymagaj\u0105c warto\u015bci, podczas gdy typy nullable s\u0105 opcjonalne, pozwalaj\u0105c na brak warto\u015bci.<\/p>\n\n\n\n<p>Domy\u015blnie regu\u0142y Java dyktuj\u0105 mapowanie i generowanie typ\u00f3w:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Typy pierwotne, takie jak &#8222;float&#8221;, nie maj\u0105 warto\u015bci null.<\/li>\n\n\n\n<li>Typy referencyjne, takie jak &#8222;String&#8221; lub &#8222;Float&#8221; s\u0105 nullable.<\/li>\n\n\n\n<li>Kolekcje akceptuj\u0105 warto\u015b\u0107 null, chyba \u017ce typ elementu jest prymitywny.<\/li>\n\n\n\n<li>Mapy akceptuj\u0105 warto\u015b\u0107 null, chyba \u017ce typ elementu jest prymitywny.<\/li>\n<\/ul>\n\n\n\n<p>U\u017cy\u0142em r\u00f3wnie\u017c adnotacji @Nonnull. Deweloperzy Hilla zdecydowali si\u0119 doda\u0107 t\u0119 adnotacj\u0119, poniewa\u017c istniej\u0105ca adnotacja `jakarta.annotation.Nonnull` nie ma zastosowania do parametr\u00f3w typu. Jest ona u\u017cywana przez generator TypeScript jako \u017ar\u00f3d\u0142o informacji o niewa\u017cno\u015bci typu.<\/p>\n\n\n\n<p>W ramach projektu wykorzystam baz\u0119 danych H2 tworzon\u0105 w pami\u0119ci aplikacji przy jej starcie. Dodam r\u00f3wnie\u017c testowe dane, aby m\u00f3c wy\u015bwietli\u0107 je po stronie frontend.<\/p>\n\n\n\n<figure class=\"wp-block-image aligncenter size-full is-resized\"><a href=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/05\/image8-2.png\"><img decoding=\"async\" width=\"997\" height=\"119\" src=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/05\/image8-2.png\" alt=\"data.sql\" class=\"wp-image-27917\" style=\"width:840px;height:auto\" srcset=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/05\/image8-2.png 997w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/05\/image8-2-300x36.png 300w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/05\/image8-2-768x92.png 768w\" sizes=\"(max-width: 997px) 100vw, 997px\" \/><\/a><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Warstwa frontend<\/strong><\/h2>\n\n\n\n<p>Kolejnym etapem jest uruchomienie projektu, umo\u017cliwiaj\u0105c Hilla automatyczne wygenerowanie plik\u00f3w gotowych do u\u017cycia po stronie frontendu.<\/p>\n\n\n\n<p>Oto jak wygl\u0105da struktura wygenerowanych plik\u00f3w po uruchomieniu projektu:<\/p>\n\n\n\n<figure class=\"wp-block-image aligncenter size-full\"><a href=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/05\/image9-2.png\"><img decoding=\"async\" width=\"282\" height=\"288\" src=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/05\/image9-2.png\" alt=\"frontend\" class=\"wp-image-27920\" style=\"object-fit:cover\"\/><\/a><\/figure>\n\n\n\n<p>CarDTO.ts odzwierciedla struktur\u0119 pliku CarDTO.java, kt\u00f3ry zosta\u0142 wcze\u015bniej zdefiniowany po stronie backendu.<\/p>\n\n\n\n<figure class=\"wp-block-image aligncenter size-full\"><a href=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/05\/image10-2.png\"><img decoding=\"async\" width=\"257\" height=\"186\" src=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/05\/image10-2.png\" alt=\"carDTO\" class=\"wp-image-27922\" style=\"object-fit:cover\"\/><\/a><\/figure>\n\n\n\n<p>Plik CarDTOModel.ts zawiera definicje p\u00f3l oraz zasady walidacyjne przypisane do poszczeg\u00f3lnych p\u00f3l w DTO dla obiektu Car.<\/p>\n\n\n\n<figure class=\"wp-block-image aligncenter size-full\"><a href=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/05\/image11-2.png\"><img decoding=\"async\" width=\"1024\" height=\"481\" src=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/05\/image11-2.png\" alt=\"kid\" class=\"wp-image-27924\" srcset=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/05\/image11-2.png 1024w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/05\/image11-2-300x141.png 300w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/05\/image11-2-768x361.png 768w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/a><\/figure>\n\n\n\n<p>Plik CarService.ts stanowi odniesienie do klasy CarService.java, zawieraj\u0105c deklaracje poszczeg\u00f3lnych metod zdefiniowanych w tej klasie.<\/p>\n\n\n\n<figure class=\"wp-block-image aligncenter size-large\"><a href=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/05\/image12-2.png\"><img decoding=\"async\" width=\"1024\" height=\"190\" src=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/05\/image12-2-1024x190.png\" alt=\"kod\" class=\"wp-image-27926\" srcset=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/05\/image12-2-1024x190.png 1024w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/05\/image12-2-300x56.png 300w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/05\/image12-2-768x143.png 768w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/05\/image12-2.png 1162w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/a><\/figure>\n\n\n\n<p>Z takim zestawem wygenerowanych plik\u00f3w przyst\u0119puj\u0119 do stworzenia widoku CarView.ts, w kt\u00f3rym dodam formularz sk\u0142adaj\u0105cy si\u0119 z dw\u00f3ch p\u00f3l tekstowych oraz przycisku, maj\u0105cych umo\u017cliwi\u0107 dodawanie nowych rekord\u00f3w. Pod formularzem dodam tabel\u0119, w kt\u00f3rej b\u0119d\u0105 wy\u015bwietlane dane.<\/p>\n\n\n\n<figure class=\"wp-block-image aligncenter size-full\"><a href=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/05\/image13-2.png\"><img decoding=\"async\" width=\"944\" height=\"632\" src=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/05\/image13-2.png\" alt=\"kod\" class=\"wp-image-27930\" srcset=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/05\/image13-2.png 944w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/05\/image13-2-300x201.png 300w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/05\/image13-2-768x514.png 768w\" sizes=\"(max-width: 944px) 100vw, 944px\" \/><\/a><\/figure>\n\n\n\n<p>Po uruchomieniu projektu mo\u017cemy zobaczy\u0107 taki wygl\u0105d aplikacji. Jak wida\u0107, nasz widok zosta\u0142 wygenerowany, podobnie jak wysuwane menu po lewej stronie. Podczas generowania projektu, Hilla domy\u015blnie dodaje takie menu w pliku MainLayout.tsx za pomoc\u0105 komponentu AppLayout. Mo\u017cna go dowolnie konfigurowa\u0107.<\/p>\n\n\n\n<figure class=\"wp-block-image aligncenter size-full\"><a href=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/05\/image14-1.png\"><img decoding=\"async\" width=\"940\" height=\"390\" src=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/05\/image14-1.png\" alt=\"my app\" class=\"wp-image-27934\" srcset=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/05\/image14-1.png 940w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/05\/image14-1-300x124.png 300w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/05\/image14-1-768x319.png 768w\" sizes=\"(max-width: 940px) 100vw, 940px\" \/><\/a><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Walidacja danych<\/strong><\/h2>\n\n\n\n<p>Walidacja danych to zapobieganie b\u0142\u0119dom oraz efektywne zarz\u0105dzanie sytuacjami, gdy dane nie spe\u0142niaj\u0105 oczekiwanych kryteri\u00f3w. W tym podrozdziale zg\u0142\u0119bimy techniki obs\u0142ugi b\u0142\u0119d\u00f3w zwi\u0105zane z walidacj\u0105 w Hilla Framework.<\/p>\n\n\n\n<p>Hilla upraszcza proces sprawdzania poprawno\u015bci danych wprowadzanych przez u\u017cytkownika, wykorzystuj\u0105c model danych zaplecza Java. Interpretuj\u0105c adnotacje Bean Validation (JSR-380) obecne w typach danych Java, p\u0142ynnie wymusza te ograniczenia na przychodz\u0105cych danych wej\u015bciowych u\u017cytkownika. Dodajmy adnotacje walidacyjne do naszych p\u00f3l w pliku CarDTO.java. Za\u0142\u00f3\u017cmy, \u017ce pola \u201ebrand\u201d i \u201emodel\u201d nie mog\u0105 by\u0107 puste oraz musz\u0105 zawiera\u0107 przynajmniej 3 znaki. Wykorzystam do tego adnotacj\u0119 @NotEmpty oraz @Size.<\/p>\n\n\n\n<figure class=\"wp-block-image aligncenter size-full\"><a href=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/05\/image15.png\"><img decoding=\"async\" width=\"831\" height=\"434\" src=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/05\/image15.png\" alt=\"kod\" class=\"wp-image-27936\" style=\"object-fit:cover\" srcset=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/05\/image15.png 831w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/05\/image15-300x157.png 300w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/05\/image15-768x401.png 768w\" sizes=\"(max-width: 831px) 100vw, 831px\" \/><\/a><\/figure>\n\n\n\n<p>Nast\u0119pnie uruchamiam projekt \u2013 sp\u00f3jrzmy, jak wygl\u0105da plik CarDTOModel.ts. Zawiera on te same zasady walidacyjne, kt\u00f3re zamie\u015bci\u0142em po stronie backendu w pliku CarDTO.java:<\/p>\n\n\n\n<figure class=\"wp-block-image aligncenter size-large\"><a href=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/05\/image16.png\"><img decoding=\"async\" width=\"1024\" height=\"588\" src=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/05\/image16-1024x588.png\" alt=\"kod\" class=\"wp-image-27938\" srcset=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/05\/image16-1024x588.png 1024w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/05\/image16-300x172.png 300w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/05\/image16-768x441.png 768w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/05\/image16.png 1417w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/a><\/figure>\n\n\n\n<p>Teraz mog\u0119 przyst\u0105pi\u0107 do pod\u0142\u0105czenia walidacji do naszego formularza w pliku CarView.ts.<\/p>\n\n\n\n<p>Podczas wykonania metody submit wykonywana jest metoda CarService.create(car), kt\u00f3ra wywo\u0142uje metod\u0119 napisan\u0105 na backend w CarService.java. Jako odpowied\u017a otrzymuje stworzony obiekt, dodaje nowo stworzony obiekt do tablicy obiekt\u00f3w \u201ecars\u201d. Na koniec formularz jest czyszczony za pomoc\u0105 metody clear().<\/p>\n\n\n\n<figure class=\"wp-block-image aligncenter size-full\"><a href=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/05\/image17-1.png\"><img decoding=\"async\" width=\"942\" height=\"517\" src=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/05\/image17-1.png\" alt=\"kod\" class=\"wp-image-27942\" srcset=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/05\/image17-1.png 942w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/05\/image17-1-300x165.png 300w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/05\/image17-1-768x422.png 768w\" sizes=\"(max-width: 942px) 100vw, 942px\" \/><\/a><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Sprawd\u017amy, jak dzia\u0142a aplikacja<\/strong><\/h2>\n\n\n\n<p>Po pr\u00f3bie wci\u015bni\u0119cia przycisku \u201eSave\u201d z nieuzupe\u0142nionymi polami w formularzu otrzymujemy informacj\u0119 pod konkretnymi polami, jakie zasady walidacyjne zadzia\u0142a\u0142y. <\/p>\n\n\n\n<p>W tym przyk\u0142adzie text field \u201eBrand\u201d zar\u00f3wno jak i text field \u201eModel\u201d s\u0105 puste, wi\u0119c zadzia\u0142a\u0142a walidacja, kt\u00f3r\u0105 napisa\u0142em po stronie backendu, stosuj\u0105c adnotacj\u0119 @NotEmpty.<\/p>\n\n\n\n<figure class=\"wp-block-image aligncenter size-full\"><a href=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/05\/image18-1.png\"><img decoding=\"async\" width=\"817\" height=\"368\" src=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/05\/image18-1.png\" alt=\"car view\" class=\"wp-image-27944\" style=\"object-fit:cover\" srcset=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/05\/image18-1.png 817w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/05\/image18-1-300x135.png 300w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/05\/image18-1-768x346.png 768w\" sizes=\"(max-width: 817px) 100vw, 817px\" \/><\/a><\/figure>\n\n\n\n<p>Teraz spr\u00f3buj\u0119 wpisa\u0107 dwuznakowe inputy w celu sprawdzenia dzia\u0142ania drugiej walidacji. Jak wida\u0107 na poni\u017cszym obrazku, zadzia\u0142a\u0142a druga walidacja, kt\u00f3r\u0105 doda\u0142em na backend, stosuj\u0105c adnotacj\u0119 @Size.<\/p>\n\n\n\n<figure class=\"wp-block-image aligncenter size-full\"><a href=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/05\/image19-1.png\"><img decoding=\"async\" width=\"815\" height=\"384\" src=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/05\/image19-1.png\" alt=\"car view\" class=\"wp-image-27946\" srcset=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/05\/image19-1.png 815w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/05\/image19-1-300x141.png 300w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/05\/image19-1-768x362.png 768w\" sizes=\"(max-width: 815px) 100vw, 815px\" \/><\/a><\/figure>\n\n\n\n<p><br><\/p>\n\n\n\n<p>Nast\u0119pnie spr\u00f3buj\u0119 wpisa\u0107 dane spe\u0142niaj\u0105ce dwa warunki walidacyjne. Formularz zaobserwowa\u0142 zmian\u0119 danych na poprawne i pozwala je zapisa\u0107.<\/p>\n\n\n\n<figure class=\"wp-block-image aligncenter size-full\"><a href=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/05\/image20-1.png\"><img decoding=\"async\" width=\"826\" height=\"340\" src=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/05\/image20-1.png\" alt=\"car view\" class=\"wp-image-27948\" srcset=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/05\/image20-1.png 826w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/05\/image20-1-300x123.png 300w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/05\/image20-1-768x316.png 768w\" sizes=\"(max-width: 826px) 100vw, 826px\" \/><\/a><\/figure>\n\n\n\n<p>Po naci\u015bni\u0119ciu przycisku \u201eSave\u201d mo\u017cemy zaobserwowa\u0107 poprawne dodanie naszych danych do tabeli z wynikami.<\/p>\n\n\n\n<figure class=\"wp-block-image aligncenter size-full\"><a href=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/05\/image21-1.png\"><img decoding=\"async\" width=\"819\" height=\"375\" src=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/05\/image21-1.png\" alt=\"car view\" class=\"wp-image-27952\" srcset=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/05\/image21-1.png 819w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/05\/image21-1-300x137.png 300w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/05\/image21-1-768x352.png 768w\" sizes=\"(max-width: 819px) 100vw, 819px\" \/><\/a><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">Przyk\u0142ad komponentu gotowego do u\u017cycia<\/h2>\n\n\n\n<p>Hilla wychodzi naprzeciw wymaganiom tworzenia aplikacji internetowych i dostarcza gotowe komponenty.<\/p>\n\n\n\n<p>Zaprezentuj\u0119 dzia\u0142anie komponentu AutoGrid. Obs\u0142uguje on funkcje sortowania, filtrowania oraz pobiera dane z backendu za pomoc\u0105 lazy loading. Osi\u0105ga si\u0119 to poprzez wywo\u0142anie metody <code>ListService&lt;T&gt;.list(Pageable pageable, @Nullable Filter filter).<\/code><\/p>\n\n\n\n<p>Na pocz\u0105tek musimy dostosowa\u0107 backend. Dodaj\u0119 interfejs JpaSpecificationExecutor do repozytorium, aby umo\u017cliwi\u0107 wykonywanie okre\u015blonych zapyta\u0144 do bazy danych.<\/p>\n\n\n\n<figure class=\"wp-block-image aligncenter size-full\"><a href=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/05\/Obraz1.png\"><img decoding=\"async\" width=\"605\" height=\"181\" src=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/05\/Obraz1.png\" alt=\"kod\" class=\"wp-image-27954\" srcset=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/05\/Obraz1.png 605w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/05\/Obraz1-300x90.png 300w\" sizes=\"(max-width: 605px) 100vw, 605px\" \/><\/a><\/figure>\n\n\n\n<p>Rozszerz\u0119 klas\u0119 CarService. Rozszerzy ona dedykowan\u0105 klas\u0119 (<code>ListRepositoryService&lt;T, ID, R> <\/code>kt\u00f3ra z kolei implementuje <code>ListService&lt;T><\/code>), kt\u00f3r\u0105 Hilla dostarcza do obs\u0142ugi komponentu Auto Grid.<\/p>\n\n\n\n<figure class=\"wp-block-image aligncenter size-full\"><a href=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/05\/Obraz2.png\"><img decoding=\"async\" width=\"605\" height=\"162\" src=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/05\/Obraz2.png\" alt=\"kod\" class=\"wp-image-27956\" style=\"object-fit:cover\" srcset=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/05\/Obraz2.png 605w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/05\/Obraz2-300x80.png 300w\" sizes=\"(max-width: 605px) 100vw, 605px\" \/><\/a><\/figure>\n\n\n\n<p>Po stronie frontendu mo\u017cemy zast\u0105pi\u0107 komponent Grid komponentem AutoGrid, kt\u00f3ry b\u0119dzie u\u017cywa\u0142 odpowiednik TypeScript naszego serwisu z backend oraz model CarDTO w parametrach.<\/p>\n\n\n\n<figure class=\"wp-block-image aligncenter size-full\"><a href=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/05\/Obraz3.png\"><img decoding=\"async\" width=\"605\" height=\"327\" src=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/05\/Obraz3.png\" alt=\"kod\" class=\"wp-image-27958\" srcset=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/05\/Obraz3.png 605w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/05\/Obraz3-300x162.png 300w\" sizes=\"(max-width: 605px) 100vw, 605px\" \/><\/a><\/figure>\n\n\n\n<p>Po uruchomieniu aplikacji mo\u017cemy zobaczy\u0107 jej wygl\u0105d.<\/p>\n\n\n\n<figure class=\"wp-block-image aligncenter size-full\"><a href=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/05\/Obraz4.png\"><img decoding=\"async\" width=\"605\" height=\"267\" src=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/05\/Obraz4.png\" alt=\"car view\" class=\"wp-image-27960\" srcset=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/05\/Obraz4.png 605w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/05\/Obraz4-300x132.png 300w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/05\/Obraz4-370x162.png 370w\" sizes=\"(max-width: 605px) 100vw, 605px\" \/><\/a><\/figure>\n\n\n\n<p>Jak wida\u0107, mamy mo\u017cliwo\u015b\u0107 sortowania i filtrowania warto\u015bci. Zobaczmy, jak dzia\u0142a sortowanie.<\/p>\n\n\n\n<figure class=\"wp-block-image aligncenter size-full\"><a href=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/05\/Obraz5.png\"><img decoding=\"async\" width=\"539\" height=\"239\" src=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/05\/Obraz5.png\" alt=\"car view\" class=\"wp-image-27962\" srcset=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/05\/Obraz5.png 539w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/05\/Obraz5-300x133.png 300w\" sizes=\"(max-width: 539px) 100vw, 539px\" \/><\/a><\/figure>\n\n\n\n<p>Widzimy, \u017ce warto\u015bci zosta\u0142y posortowane wed\u0142ug pola Brand. Spr\u00f3bujmy odfiltrowa\u0107 warto\u015bci Model.<\/p>\n\n\n\n<figure class=\"wp-block-image aligncenter size-full\"><a href=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/05\/Obraz6.png\"><img decoding=\"async\" width=\"571\" height=\"257\" src=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/05\/Obraz6.png\" alt=\"car view\" class=\"wp-image-27964\" srcset=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/05\/Obraz6.png 571w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/05\/Obraz6-300x135.png 300w\" sizes=\"(max-width: 571px) 100vw, 571px\" \/><\/a><\/figure>\n\n\n\n<p>Warto\u015bci pola Model zosta\u0142y poprawnie odfiltrowane. Jak mo\u017cemy zauwa\u017cy\u0107, Hilla dysponuje szerok\u0105 gam\u0105 rozwi\u0105za\u0144, kt\u00f3re mog\u0105 nam pom\u00f3c w implementacji naszych projekt\u00f3w.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Konfiguracja i wdro\u017cenie<\/strong><\/h2>\n\n\n\n<p>W projekcie Hilla mo\u017cna skonfigurowa\u0107 zar\u00f3wno frontend, jak i backend. Aby skonfigurowa\u0107 frontend, mo\u017cemy u\u017cy\u0107 pliku tsconfig.json, w kt\u00f3rym konfigurujemy kompilator TypeScript. Do konfiguracji backendu mo\u017cemy u\u017cy\u0107 pliku pom.xml, w kt\u00f3rym da si\u0119 dodawa\u0107 zale\u017cno\u015bci i zarz\u0105dza\u0107 produkcyjnymi kompilacjami naszej aplikacji.<\/p>\n\n\n\n<p>Je\u015bli chcemy wygenerowa\u0107 kompilacj\u0119 produkcyjn\u0105, wystarczy uruchomi\u0107 polecenie:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">mvn clean package -Pproduction<\/pre>\n\n\n\n<p>Wykonanie tego polecenia spowoduje utworzenie pliku JAR ze wszystkimi zale\u017cno\u015bciami i zasobami frontendu, gotowego do wdro\u017cenia.<\/p>\n\n\n\n<p><a href=\"https:\/\/hilla.dev\/docs\/react\/guides\/production\/cloud-providers\" target=\"_blank\" aria-label=\" (opens in a new tab)\" rel=\"noreferrer noopener\" class=\"ek-link\" rel=\"nofollow\" >Dokumentacja Hilla<\/a> zapewnia gotowe instrukcje wdra\u017cania u najlepszych dostawc\u00f3w us\u0142ug w chmurze (tj. AWS, Azure, Google Cloud, Heroku). \u00a0<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Podsumowanie<\/strong><\/h2>\n\n\n\n<p>W artykule stara\u0142em si\u0119 rzuci\u0107 \u015bwiat\u0142o na fascynuj\u0105cy \u015bwiat frameworka Hilla, ukazuj\u0105c jego unikalne zalety i potencja\u0142 w szybkim tworzeniu aplikacji fullstack. Mam nadziej\u0119, \u017ce uda\u0142o mi si\u0119 przekaza\u0107, jak w prosty spos\u00f3b mo\u017cemy wykorzysta\u0107 to narz\u0119dzie do efektywnej integracji warstwy frontendowej i backendowej, tworz\u0105c sp\u00f3jne i wydajne aplikacje webowe.<\/p>\n\n\n\n<p>Hilla u\u0142atwia nie tylko proces tworzenia aplikacji, ale tak\u017ce skraca drog\u0119 do osi\u0105gni\u0119cia pe\u0142nej funkcjonalno\u015bci. Podkre\u015blam, \u017ce Hilla oferuje szeroki wachlarz gotowych komponent\u00f3w, usprawniaj\u0105c tym samym proces budowy interfejsu u\u017cytkownika. Dodatkowo, framework dostarcza rozbudowane implementacje zabezpiecze\u0144, co pozwala z \u0142atwo\u015bci\u0105 dba\u0107 o bezpiecze\u0144stwo aplikacji.<\/p>\n\n\n\n<p>Z racji, \u017ce Hilla jest inicjatyw\u0105 open source, zach\u0119cam was do brania udzia\u0142u w tym projekcie, gdzie mo\u017cecie poszerza\u0107 swoje umiej\u0119tno\u015bci i zapisa\u0107 si\u0119 na kartach historii. Na <a href=\"https:\/\/hilla.dev\/docs\/react\/guides\/production\/cloud-providers\" target=\"_blank\" aria-label=\" (opens in a new tab)\" rel=\"noreferrer noopener\" class=\"ek-link\" rel=\"nofollow\" >oficjalnej stronie<\/a> znajdziecie dokumentacj\u0119, a tak\u017ce pe\u0142en zakres dost\u0119pnych komponent\u00f3w i narz\u0119dzi, kt\u00f3re sprawi\u0105, \u017ce tworzenie aplikacji stanie si\u0119 jeszcze bardziej efektywne i przyjemne.<\/p>\n\n\n<div class=\"kk-star-ratings kksr-auto kksr-align-left kksr-valign-bottom\"\n    data-payload='{&quot;align&quot;:&quot;left&quot;,&quot;id&quot;:&quot;27902&quot;,&quot;slug&quot;:&quot;default&quot;,&quot;valign&quot;:&quot;bottom&quot;,&quot;ignore&quot;:&quot;&quot;,&quot;reference&quot;:&quot;auto&quot;,&quot;class&quot;:&quot;&quot;,&quot;count&quot;:&quot;6&quot;,&quot;legendonly&quot;:&quot;&quot;,&quot;readonly&quot;:&quot;&quot;,&quot;score&quot;:&quot;5&quot;,&quot;starsonly&quot;:&quot;&quot;,&quot;best&quot;:&quot;5&quot;,&quot;gap&quot;:&quot;11&quot;,&quot;greet&quot;:&quot;&quot;,&quot;legend&quot;:&quot;5\\\/5 ( votes: 6)&quot;,&quot;size&quot;:&quot;18&quot;,&quot;title&quot;:&quot;Hilla: optymalna integracja technologii, czyli Spring Boot i React w jednym miejscu&quot;,&quot;width&quot;:&quot;139.5&quot;,&quot;_legend&quot;:&quot;{score}\\\/{best} ( {votes}: {count})&quot;,&quot;font_factor&quot;:&quot;1.25&quot;}'>\n            \n<div class=\"kksr-stars\">\n    \n<div class=\"kksr-stars-inactive\">\n            <div class=\"kksr-star\" data-star=\"1\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" data-star=\"2\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" data-star=\"3\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" data-star=\"4\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" data-star=\"5\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n    <\/div>\n    \n<div class=\"kksr-stars-active\" style=\"width: 139.5px;\">\n            <div class=\"kksr-star\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n    <\/div>\n<\/div>\n                \n\n<div class=\"kksr-legend\" style=\"font-size: 14.4px;\">\n            5\/5 ( votes: 6)    <\/div>\n    <\/div>\n","protected":false},"excerpt":{"rendered":"<p>W \u015bwiecie rozproszonych system\u00f3w webowych, utrzymanie r\u00f3wnowagi mi\u0119dzy backendem a frontendem cz\u0119sto jest wyzwaniem, kt\u00f3remu nie\u0142atwo sprosta\u0107. Pracuj\u0105c z oddzielnymi &hellip; <a class=\"continued-btn\" href=\"https:\/\/sii.pl\/blog\/hilla-optymalna-integracja-technologii-czyli-spring-boot-i-react-w-jednym-miejscu\/\">Continued<\/a><\/p>\n","protected":false},"author":632,"featured_media":27967,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"_editorskit_title_hidden":false,"_editorskit_reading_time":0,"_editorskit_is_block_options_detached":false,"_editorskit_block_options_position":"{}","inline_featured_image":false,"footnotes":""},"categories":[1314],"tags":[2427,2210,1546,1512,991],"class_list":["post-27902","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-development-na-twardo","tag-digital","tag-hilla","tag-przeglad-narzedzi","tag-poradnik","tag-react"],"acf":[],"aioseo_notices":[],"republish_history":[],"featured_media_url":"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/05\/Hilla-optymalna-integracja-technologii-czyli-Spring-Boot-i-React-w-jednym-miejscu.jpg","category_names":["Development na twardo"],"_links":{"self":[{"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/posts\/27902"}],"collection":[{"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/users\/632"}],"replies":[{"embeddable":true,"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/comments?post=27902"}],"version-history":[{"count":2,"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/posts\/27902\/revisions"}],"predecessor-version":[{"id":27966,"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/posts\/27902\/revisions\/27966"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/media\/27967"}],"wp:attachment":[{"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/media?parent=27902"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/categories?post=27902"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/tags?post=27902"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}