У сучасному світі розподілених веб-систем підтримка балансу між бекендом і фронтендом часто стає проблемою, вирішити яку нелегко. Працюючи з окремими рівнями, розробники нерідко стикаються з проблемами, пов’язаними з синхронізацією, комунікацією та можливістю масштабування. На щастя, на горизонті з’явилося унікальне рішення – Hilla.
У цій статті ми дізнаємося, яким чином Hilla забезпечує злагоджену комунікацію між бекендом і фронтендом, гарантуючи при цьому ефективність. Потім ми зосередимося на валідації форм і покажемо, у який спосіб Hilla робить цей процес простішим, безпечнішим та ефективнішим.
Що таке Hilla?
Hilla – це інноваційна базова структура, створена командою Vaadin. Вона поєднує в собі інструмент Spring Boot та бібліотеку React. Вона пропонує ефективну та просту інтеграцію та вирішує проблему підтримки окремих бекенд та фронтенд шарів. Вона також забезпечує зручність та ефективність у процесі розробки веб-застосунків.
Структура проєкту Hilla
Щоб почати працювати з Hilla, нам потрібно встановити на комп’ютері NodeJS та інтерфейс командного рядка npm (npx вже вбудований у npm, починаючи з версії 5.2.0).
Щоб почати працювати з Hilla, необхідно створити проєкт. Нижче наведено команду, яка дозволяє це зробити:
npx @hilla/cli init hilla-blog
Ось як виглядає структура каталогів після створення проєкту:
- Фронтенд (React)
- frontend/components – цекаталог, що містить React-компоненти, з яких вибудовується інтерфейс користувача. Сюди входять візуальні та функціональні елементи, такі як кнопки, форми або вкладки.
- frontend/themes – цекаталог, присвячений графічним стилям і темам. Він містить файли з таблицями стилів, налаштуваннями кольорів та шрифтів, що дозволяє легко керувати зовнішнім виглядом вашого застосунку..
- frontend/util – цекаталог з інструментами та допоміжними функціями, які можна використовувати в різних місцях проєкту. Він містить функції загального призначення, які полегшують процес маніпулювання даними або виконання певних операцій.
- frontend/views – цекаталог з поданнями, тобто основними структурами сторінок у застосунку. Тут знаходяться файли, що відповідають за візуалізацію певних секцій інтерфейсу користувача.
- Бекенд (Spring Boot)
- src/main/java/com/example/application – цекаталог вихідних текстів на стороні сервера, який містить серверні Java-подання. У ньому знаходиться файл Applicaiton.java, який є точкою входу на сервер.
Така структура проєкту полегшує навігацію та організовує код для підтримки як фронтенд, так і бекенд розробки. Розділяючи каталоги «frontend» і «src», Hilla дозволяє зосередитися на ефективній роботі над обома рівнями програми.
Як працює Hilla?
Hilla дозволяє викликати методи Java з TypeScript. Ключовим елементом цієї функції є анотація @BrowserCallable. Всі загальнодоступні методи в класі, позначені цією анотацією, стають доступними для виклику на стороні інтерфейсу. Під час запуску проєкту Hilla генерує TypeScript-еквіваленти структур даних, що використовуються в класі, позначеному анотацією @BrowserCallable. Крім того, вона створює еквівалент цього класу, що дозволяє плавно і безперешкодно використовувати ці методи на стороні інтерфейсу.
Демонстрація роботи Hilla на прикладі проєкту
Внутрішній шар
Для цієї статті я підготую шар на стороні інтерфейсу, що складається з логічного об’єкта, сховища, dto, диспетчера пам’яті і сервісу, щоб продемонструвати роботу базової структури Hilla.
- Логічний об’єкт:
- Сховище:
- DTO:
- Диспетчера пам’яті (я буду використовувати інструмент MapStruct):
- Сервіс:
Я додав до сервісу два методи:
- findAll(), який буде використовуватися для пошуку всіх записів Car,
- create(CarDTO carDTO), який буде використовуватися для створення нового запису Car.
У сервісі я використовував метод @BrowserCallable, щоб умовжливити виклик методів з React-застосунку. Крім того, я використав анотацію @AnonymousAllowed, щоб відключити контроль доступу, який передбачає Hilla (я не рекомендую робити це в застосунку – я роблю це виключно для цілей цієї статті). Я також використав анотацію @Nonnull. Генератор TypeScript використовує її як джерело інформації про типи, які допускають чи не допускають порожні значення.
Типи, які не допускають порожні значення, є обов’язковими, тобто вимагають наявності значень, тоді як типи, які допускають порожні значення, є необов’язковими, тобто допускають відсутність значень. За замовчуванням, відображення та генерацію типів диктують правила Java:
- Примітивні типи, такі як «float», не допускають порожні значення.
- Довідкові типи, такі як «String» або «Float», допускають порожні значення.
- Колекції приймають порожні значення, якщо тип елемента не є примітивним.
- Карти приймають порожні значення, якщо тип елемента не є примітивним.
Для перетворення типів, які допускають порожні значення, у типи, які не допускають порожні значення, ви можете застосувати анотацію @Nonnull. Розробники Hilla вирішили додати цю анотацію, оскільки існуюча анотація «jakarta.annotation.Nonnull» не застосовується до параметрів типів.
В рамках проєкту я буду використовувати базу даних H2, яка створюється в пам’яті застосунку під час запуску. Я також додам тестові дані для їх відображення на стороні інтерфейсу.
Інтерфейсний шар
Наступним кроком є запуск проєкту, що дозволяє Hilla автоматично генерувати файли, готові до використання на стороні інтерфейсу.
Ось як виглядає структура згенерованих файлів після запуску проєкту:
CarDTO.ts відображає структуру файлу CarDTO.java, яка була раніше визначена на стороні сервера.
Файл PlikThe CarDTOModel.ts містить визначення полів і правила перевірки, призначені для окремих полів у DTO для об’єкта Car.
Файл CarService.ts посилається на клас CarService.java, що містить заяви про різні методи, визначені у цьому класі.
З таким набором згенерованих файлів я перейшов до створення подання CarView.ts, в якому додам форму, що складається з двох текстових полів і кнопки для додавання нових записів. Під формою я додам таблицю для відображення даних.
Після запуску проєкту ми бачимо зовнішній вигляд застосунку. Наше подання і меню, що випадає зліва, вже згенеровано. За замовчуванням Hilla додає таке меню до файлу MainLayout.tsx під час генерації проєкту за допомогою компонента AppLayout. Його можна налаштовувати довільним чином.
Валідація даних
Валідація даних дозволяє уникати помилок та ефективно вирішувати ситуації, коли дані не відповідають очікуваним критеріям. У цьому підрозділі ми розглянемо методи обробки помилок, пов’язаних з валідацією в базовій структурі Hilla.
Hilla спрощує перевірку даних, які вводяться користувачем, використовуючи внутрішню модель даних Java. Інтерпретація анотацій Bean Validation (JSR-380) у ваших типах даних Java легко застосовує ці обмеження до даних, які вводяться користувачем.
Додамо до наших полів у файлі CarDTO.java валідаційні анотації. Припустимо, що поля «бренд» і «модель» не можуть бути порожніми і повинні містити щонайменше 3 символи. Для цього я використаю анотації @NotEmpty та @Size.
Далі я запускаю проєкт. Погляньмо, як виглядає файл CarDTOModel.ts. Він містить ті ж самі правила валідації, які я розмістив на стороні сервера у файлі CarDTO.java.
Тепер я можу підключити валідацію до нашої форми у файлі CarView.ts.
Під час виконання методу submit виконується метод CarService.create(car), який викликає метод, написаний на стороні сервера в CarService.java. Він отримує створений об’єкт у відповідь і додає новостворений об’єкт до масиву об’єктів «cars». Наприкінці форма очищається за допомогою методу clear().
Погляньмо, як працює застосунок
Коли ви намагаєтеся натиснути кнопку «Зберегти» під формою з незаповненими полями, ви отримуєте інформацію під конкретними полями про те, які правила валідації спрацювали.
У цьому прикладі текстові поля «Бренд» і «Модель» порожні, тому спрацювала валідація, яку я написав на стороні сервера з використанням анотації @NotEmpty.
Тепер я спробую ввести двосимвольні дані, щоб перевірити працездатність другої валідації. Як видно на зображенні нижче, друга валідація, яку я додав до серверної частини за допомогою анотації @Size, спрацювала.
Потім я спробую ввести дані, які відповідають двом умовам валідації. Форма побачить, що дані змінилися на валідні, і дозволить їх зберегти.
Після натискання кнопки «Зберегти» ми можемо спостерігати коректне додавання наших даних до таблиці результатів.
Приклад компонента, готового до використання
Hilla відповідає вимогам розробки веб-застосунків і надає готові компоненти. Я розповім про роботу компонента Auto Grid. Він підтримує функції сортування та фільтрації, а також отримує дані з сервера, використовуючи відкладене завантаження. Це досягається викликом методу ListService<T>.list(Pageable pageable, @Nullable Filter filter)
Для початку нам потрібно налаштувати серверну частину. Я додаю інтерфейс JpaSpecificationExecutor до сховища, щоб активувати певні запити до бази даних.
Я додам розширення до CarService. Воно розширить спеціальний клас (ListRepositoryService<T, ID, R>, який в свою чергу реалізує ListService<T>), передбачений у Hilla для роботи компонента Auto Grid.
На стороні інтерфейсу ми можемо замінити наш компонент Grid на компонент AutoGrid, який отримає еквівалент TypeScript нашого сервісу на стороні сервера і модель CarDTO в параметрах.
Після запуску застосунку ми бачимо, як це виглядає.
Ми можемо сортувати та фільтрувати значення. Погляньмо, як працює сортування.
Ми бачимо, що значення були відсортовані за полем Brand. Спробуймо відфільтрувати значення Model.
Значення поля Model були відфільтровані правильно. Сподіваюся, я продемонстрував, що Hilla має широкий спектр рішень, хоча й використав у прикладі лише один з багатьох доступних компонентів.
Конфігурація та розгортання
У проєкті Hilla можна налаштувати як інтерфейс, так і серверну частину. Для конфігурації інтерфейсу ми можемо скористатись файлом tsconfig.json, який налаштовує компілятор TypeScript. Для конфігурації серверної частини ми можемо скористатись файлом pom.xml, який додає залежності та керує збірками коду для промислової експлуатації нашого застосунку.
Якщо ми хочемо згенерувати збірку коду для промислової експлуатації, нам просто потрібно запустити команду:
mvn clean package -Pproduction
Внаслідок виконання цієї команди буде створено JAR-файл з усіма залежностями та ресурсами інтерфейсу, готовими до розгортання. Документація Hilla містить готові інструкції з розгортання для провідних хмарних провайдерів (наприклад, AWS, Azure, Google Cloud та Heroku).
Підсумок
У цій статті я спробував висвітлити захоплюючий світ базової структури Hilla, продемонструвавши її унікальні переваги та потенціал у швидкій розробці повностекових застосунків. Сподіваюся, я зміг пояснити, як можна легко використовувати цей інструмент для ефективної інтеграції інтерфейсу і серверної частини, створюючи узгоджені та ефективні веб-застосунки.
Hilla спрощує процес розробки застосунків і скорочує шлях до реалізації повної функціональності. Підкреслю, що Hilla пропонує широкий вибір готових компонентів, що спрощує процес побудови інтерфейсу користувача. Крім того, ця базова структура надає широкі можливості для реалізації засобів безпеки, що дозволяє легко забезпечити безпеку застосунків.
Оскільки Hilla є проєктом з відкритим вихідним кодом, я закликаю вас взяти участь у його реалізації. Тут ви зможете розширити свої навички та стати одним з його співтворців. На офіційному сайті проєкту є документація і повний набір доступних компонентів та інструментів, які зроблять розробку застосунків ще легшою і більш ефективною.