JavaRush /Java блог /Random UA /Завоювання Spring Boot
Surplus
37 рівень
Москва

Завоювання Spring Boot

Стаття з групи Random UA
Доброго часу доби, шановний Читачу! І приємно познайомитися, навіть якщо основною причиною зазирнути в скромну тему про перше знайомство з розробкою на Spring Boot стала помпезна назва. Хотілося б поділитися досвідом виконання вступного завдання для стажування на порталі JavaRush, викладаючи огляд з боку звичайного студента технічного університету, який бажає перевірити на міцність накопичені знання. Завоювання Spring Boot - 1Жодним чином не заперечую можливу наявність грубості в доданому коді чи методиці мислення, і вітаю конструктивну критику, адже саме завдяки “гулям та саднам” вдається розвиватися у професійному напрямку. Більше того, зовсім не претендую на звання “панацеї” у вирішенні поставлених умов та навмисно упускаю окремі фрагменти програми, залишаючи ключовим значенням входження у відносно складну тему без найменших наслідків для нервової системи. Мабуть, необачно заперечувати очевидне: мені було важко і зовсім нічого не зрозуміло до певного моменту. І якщо Ви відчуваєте схожі відчуття від першої зустрічі із завданням, то “Ласкаво просимо!”. Напишемо web-додаток на Spring Boot за спрощеною аналогією вступного тесту на стажування з використанням двигуна шаблонів Thymeleafтаquery-запитами на локальний сервер MySQL для фільтрації вхідного масиву інформації Отже, почнемо!

Spring Boot. Що за звір та як його готувати?

Якщо коротко і лаконічно, - чудовий інструмент від компанії Pivotel для збереження дорогоцінного часу в процесі створення програми, що виключає потребу прямого підключення сторонніх бібліотек, написання великого полотна мапірування та сервлетів. Достатньо скористатися збирачем Spring Initializr , інтегрованим у IntelliJ IDEA Ultimate Edition (File - New - Project... - Spring Initializr) або розташованому на web-сервісі start.spring.io , вказуючи пакети для включення з широкого переліку пропозицій.
Завоювання Spring Boot - 2
Наслідуючи висунуте технічне завдання, скористаємося джентльменським набором, стандартним для створення простого web-додатка з урахуванням використання бази MySQL :
  • WEB – основний компонент для розробки web-додатку, що включає локальний сервер Apache Tomcat за стандартною адресаою localhost:8080 та універсальний фреймворк Spring MVC.

  • DevTools — використовується для швидкого перезапуску програми у гарячій JVM при виявленні змін у скомпілюваному коді або шаблонах; навіть звільняє від очищення cache у Thymeleaf, якщо обраний двигун включений у проект.

  • JPA - технологія потрібна для роботи з базами даних і забезпечує об'єктно-реляційне відображення Java об'єктів, надає API ( Hibernate у нашому випадку) для управління, збереження та отримання сутностей.

  • Thymeleaf (Mustache, AngularJS, Vaadin і далі) - двигун шаблонів для візуалізації програми; завдяки відносному знайомству з принципами html зупинив вибір на Thymeleaf, що висунув мову на наріжний стовп світу.

  • MySQL - підключає драйвера Java Database Connectivity для виконання SQL-запитів до бази даних.
Після остаточного вибору компонентів та створення отримуємо звичайну архітектуру web-додатки з готовими для подальшого наповнення директоріями. Фрагменти для взаємодії з візуальною частиною, будь то графічні стилі CSS, стандартні сторінки HTML або функціонал JavaScript, повинні розташовуватись у “resources”, а back-end складова, відповідно, мається на увазі для розміщення у “java”. Окремо варто звернути увагу на файл pom.xml у кореневому діапазоні, що зберігає структуру проекту та залежність між компонентами. Якщо потрібно надалі розширити функціонал додатковими пакетами або видалити зайве, слід провести маніпуляції між тегів <dependencies></dependencies>відповідно до подібного методу.
Завоювання Spring Boot - 3

Перші кроки у велике майбутнє

Далі виникає досить цікаве й цілком логічно обґрунтоване питання: “А що робити тепер? Як це працюватиме?”. Програма будується на принципах Model-View-Controller: організує зчитування сутностей з підключеної бази даних (Model) і відображається в інтерфейсі користувача з елементами управління (View); зв'язок між компонентами та виконання дій відповідно до переданих запитів виконується завдяки Controller. Саме створення ключових елементів є опорною точкою для продовження розробки. Щоб уникнути слизької доріжки та зберігати повагу товаришів на трудовій ниві, слід розташовувати компоненти у відповідних директоріях (скажімо, помістити файл Controller у папку controllers у гілку “java”) і дбайливо зберігати порядок на робочому місці.

Сутність - маленька деталь у великому механізмі

Або інакше — наша Модель згідно з поставленими в задачі умовами. Відступаючи від тематики обговорення та повертаючись до вступного проекту, можна впевнено стверджувати про мінімальні відмінності між завданнями та дотримуватися подальшого огляду усередненої концепції. Скажімо, нотаток у записнику, що включають:
  • Ідентифікаційний номер для визначення розташування у загальному потоці;
  • Текстове повідомлення із певної кількості символів;
  • Дату додавання користувачем до загального переліку;
  • Логічну змінну визначення “Зроблено чи зроблено” (“Прочитано чи не прочитано”).
Отже, створимо клас Note у директорії з назвою “entity” та додамо відповідні поля:
@Entity
public class Note {

   @Id
   @GeneratedValue
   private int id;
   private String message;
   private Date date;
   private boolean done;

   public Note() {
   }

   public Note(String message) {
       this.message = message;
       this.date = new Date();
       this.done = false;
   }
}
Чергове відхилення від теми обговорення для більшого розуміння того, що відбувається з теоретичної позиції. Зв'язок між компонентами в Spring задається анотаціями, - Спеціальними покажчиками перед об'єктами, кожен із яких виконує певну роль механізмі і починається символом “@”. Анотація @Entity вказує Spring Boot на належність наступних даних класу до “Сутності”, а @Id та @GeneratedValue задають обране поле ідентифікатором з автоматичною генерацією ітератора під час обробки масиву інформації. Спеціально упускаю додавання стандартних Getter and Setter для збільшення компактності візуального формату. Далі, зважаючи на використання бази даних для зберігання записів, переходимо на наступний щабель у розробці програми: створимо в директорії “repository” інтерфейс NoteRepository, - сполучний елемент у ланцюжку обміну, - і успадкуємо найбільш підходящий для подальшої роботи репозиторій із зазначенням сутності, що зберігається і цілісного ітератора для звернення.
public interface NoteRepository extends JpaRepository<Note, Integer> {
}
Власне, все. Коротко та лаконічно. Тепер Spring Boot використовуватиме створений компонент для організації взаємодій з базою даних. Є відносно багато типів успадкованих репозиторіїв з різним потенціалом можливої ​​дії. JpaRepository знаходиться на вершині сходів і має найбільший потенціал, включаючи нижчі CrudRepository і PageAndSortingRepository. Більше не заглиблюватимемося і відходитимемо від теми, адже окремі тонкощі можна дізнатися на сайті Pivotel у технічній документації. Тепер, після втілення образу даних та вказівки способів зв'язку на стороні програми, потрібно звернути увагу на створення бази MySQL у відповідному зовнішньому середовищі MySQL Workbench, заздалегідь встановленої на настільну платформу в збірці від офіційного розробника з додатковими пакетами для створення локального сервера:
Завоювання Spring Boot - 4
Далі, слідуючи за вказівками середовища після натискання на іконку з поточним локальним сервером у головному вікні, створюємо схему таблиці згідно з полями нашої сутності (Note) та заповнюємо її відповідними даними. Слід окремо уточнити тонкощі діалекту MySQL, які наполегливо потребують уваги для успішного досягнення бажаного результату:
  • Окремого булева типу не існує. Будь-які дії з обробкою запитів перетворюють "true" або "false" на бітове значення "1" або "0" відповідно;
  • Збереження дати повністю відбувається у типі Timestamp. Якщо використовувати звичний до мозку кісток Date, доведеться обмежитися лише положенням у календарі.
Завоювання Spring Boot - 5
Після завершення підготовчих дій, вказуємо “MySQL Workbench” на відправку даних у локальний сервер натисканням на значок з “блискавкою” на панелі інструментів. Тепер, якщо додавання інформації пройшло коректно, можемо впевнено повертатися до рідної IDE для подальшого продовження розробки, додаючи конфігурацію поточної бази до application.properties (зазвичай, знаходиться в директорії “resources”):
spring.datasource.url=jdbc:mysql://localhost:3306/test?useSSL=false
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.jpa.show-sql=true
spring.jpa.hibernate.ddl-auto=update
І остаточно прив'язуючи суть Note до MySQL за допомогою анотацій. @Table вказує використання таблиці з вибраним ім'ям і схемою, а @Column - приналежність змінних до певному полю.
@Entity
@Table(name = "test", schema = "test", catalog = "")
public class Note {

   @Id
   @GeneratedValue
   private int id;
   @Column(name = "message")
   private String message;
   @Column(name = "date")
   private Date date;
   @Column(name = "done")
   private boolean done;

   public Note() {
   }

   public Note(String message) {
       this.message = message;
       this.date = new Date();
       this.done = false;
   }
}

Вигляд або інтерфейс користувача

На жаль, можна сміливо стверджувати наступне: "Візуалізація програми стане основним каменем спотикання без наявності найменших теоретичних або практичних знань". Будучи відвертим, front-end складова зайняла разючий обсяг від загальної кількості роботи і впевнено тріпала нерви протягом тривалого часового періоду. Але завдяки дивовижній простоті Thymeleaf вдалося знайти відповідний компроміс після низки феєричних поразок. Подальше обговорення буде вестися саме про тонкощі використання обраного двигуна, хоча загальна концепція дотримується подібного положення. Основна методика полягає у можливості використання найчистішого HTML та складання кінцевого відображення з окремих фрагментів для виключення множинного повторення ідентичних ділянок. Припустимо, архітектура інтерфейсу користувача складається з головної сторінки, що складається з навігаційної панелі з елементами управління (додавання нового запису, повернення на головну сторінку) і динамічної таблиці для відображення сутностей з сортуванням за часом додавання нотатки в напрямку збільшення (ASC) або зменшення (DESC) значення. Приймемо за стандартне положення відображення всіх записів зростання. Згідно з ієрархічною політикою вибраного движка шаблонів, складові елементи візуалізації повинні бути розташовані на гілці “templates” у директорії “resources”. Отже, подальші маніпуляції з компонентами беруть до уваги висунуті умови. Створимо головну сторінку з ім'ям "index" (або будь-яким іншим відповідно до особистих уподобань) на шаблоні html5. Наприклад: що складається з навігаційної панелі з елементами керування (додавання нового запису, повернення на головну сторінку) та динамічної таблиці для відображення сутностей із сортуванням за часом додавання нотатки у напрямку збільшення (ASC) або зменшення (DESC) значення. Приймемо за стандартне положення відображення всіх записів зростання. Згідно з ієрархічною політикою вибраного движка шаблонів, складові елементи візуалізації повинні бути розташовані на гілці “templates” у директорії “resources”. Отже, подальші маніпуляції з компонентами беруть до уваги висунуті умови. Створимо головну сторінку з ім'ям "index" (або будь-яким іншим відповідно до особистих уподобань) на шаблоні html5. Наприклад: що складається з навігаційної панелі з елементами керування (додавання нового запису, повернення на головну сторінку) та динамічної таблиці для відображення сутностей із сортуванням за часом додавання нотатки у напрямку збільшення (ASC) або зменшення (DESC) значення. Приймемо за стандартне положення відображення всіх записів зростання. Згідно з ієрархічною політикою вибраного движка шаблонів, складові елементи візуалізації повинні бути розташовані на гілці “templates” у директорії “resources”. Отже, подальші маніпуляції з компонентами беруть до уваги висунуті умови. Створимо головну сторінку з ім'ям "index" (або будь-яким іншим відповідно до особистих уподобань) на шаблоні html5. Наприклад: повернення на головну сторінку) та динамічної таблиці для відображення сутностей із сортуванням за часом додавання нотатки у напрямку збільшення (ASC) або зменшення (DESC) значення. Приймемо за стандартне положення відображення всіх записів зростання. Згідно з ієрархічною політикою вибраного движка шаблонів, складові елементи візуалізації повинні бути розташовані на гілці “templates” у директорії “resources”. Отже, подальші маніпуляції з компонентами беруть до уваги висунуті умови. Створимо головну сторінку з ім'ям "index" (або будь-яким іншим відповідно до особистих уподобань) на шаблоні html5. Наприклад: повернення на головну сторінку) та динамічної таблиці для відображення сутностей із сортуванням за часом додавання нотатки у напрямку збільшення (ASC) або зменшення (DESC) значення. Приймемо за стандартне положення відображення всіх записів зростання. Згідно з ієрархічною політикою вибраного движка шаблонів, складові елементи візуалізації повинні бути розташовані на гілці “templates” у директорії “resources”. Отже, подальші маніпуляції з компонентами беруть до уваги висунуті умови. Створимо головну сторінку з ім'ям "index" (або будь-яким іншим відповідно до особистих уподобань) на шаблоні html5. Наприклад: складові елементи візуалізації повинні бути розташовані на гілці “templates” у директорії “resources”. Отже, подальші маніпуляції з компонентами беруть до уваги висунуті умови. Створимо головну сторінку з ім'ям "index" (або будь-яким іншим відповідно до особистих уподобань) на шаблоні html5. Наприклад: складові елементи візуалізації повинні бути розташовані на гілці “templates” у директорії “resources”. Отже, подальші маніпуляції з компонентами беруть до уваги висунуті умови. Створимо головну сторінку з ім'ям "index" (або будь-яким іншим відповідно до особистих уподобань) на шаблоні html5. Наприклад:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
     xmlns:th="http://www.thymeleaf.org">
<head th:replace="fragments/head :: head"></head>
<body>
<div class="container">
   <div th:replace="fragments/header :: header"></div>
   <div th:if="${not #lists.isEmpty(notes)}">
       <div th:replace="operations/list :: notebook"></div>
   </div>
   <div th:replace="fragments/footer :: footer"></div>
</div>
</body>
</html>
І так, розкладемо по поличках ключову складову кінцевої програми. Thymeleaf використовує окремий синтаксис для вказівки застосування процедур і починається з ключового слова “th:”, посилання на бібліотеку з яким приєднується в обов'язковому порядку у тезі <html>.
<div th:if="${not #lists.isEmpty(notes)}">
Операція "if" зовсім не відрізняється від звичного способу дій і перевіряє вхідний атрибут "notes" на наявність об'єктів для подальшого відображення. Слід окремо згадати про перехльостування теми з використанням Controller, беручи до уваги застосування цього для організації взаємодії моделі та візуалізації. Багато туманних моментів набувають обрисів надалі, просто поверніться назад за наявності бажання.
<head th:replace="operations/list :: notebook"></head>
Операція "replace" вказує на заміну "заглушки" або діючого блоку на вибраний фрагмент із поточної або окремої сторінки - останній випадок наочно спостерігається у прикладі. Ми копіюємо фрагмент з назвою “notebook” з “list.html” директорії “operations” у <div></div> файлу “index”, повністю замінюючи вміст у кінцевому пункті призначення. Вихідний має такий зміст:
<!DOCTYPE html>
<!--suppress ALL -->
<html xmlns="http://www.w3.org/1999/xhtml"
     xmlns:th="http://www.thymeleaf.org">

<div th:fragment="notebook">
   <table class="table table-bordered table-hover horizontal-align">
       <thead>
       <tr>
           <th style="width: 5%">#</th>
           <th style="width: 60%">Message</th>
           <th class="dropdown" style="width: 20%">Date
               <a th:href="@{'/sort/{sortDate}' (sortDate = 'ASC')}"><i class="fa fa-chevron-circle-up"></i></a>
               <a th:href="@{'/sort/{sortDate}' (sortDate = 'DESC')}"><i class="fa fa-chevron-circle-down"></i></a>
           </th>
           <th style="width: 5%">Done</th>
           <th style="width: 5%">Edit</th>
           <th style="width: 5%">Delete</th>
       </tr>
       </thead>
       <tbody>
       <tr th:each="note : ${notes}">
           <td th:text="${note.id}" style="text-align: center">#</td>
           <td th:text="${note.message}">Message</td>
           <td th:text="${#dates.format(note.date, 'EEE, d MMM yyyy HH:mm')}" style="text-align: center">Date</td>
           <td style="text-align: center">
               <i th:if="${note.done} == true" class="fa fa-plus-square-o" style="font-size:20px;color:#337ab7"></i>
               <i th:if="${note.done} == false" class="fa fa-minus-square-o" style="font-size:20px;color:#337ab7"></i>
           </td>
           <td style="text-align: center"><a th:href="@{'/edit/{id}'(id=${note.id})}"><i class="fa fa-edit" style="font-size:20px"></i></a></td>
           <td style="text-align: center"><a th:href="@{'/delete/{id}'(id=${note.id})}"><i class="fa fa-trash" style="font-size:20px"></i></a></td>
       </tr>
       </tbody>
   </table>
</div>
</html>
Знову звернемося до конструктивного огляду та пройдемо по використаним функціям Thymeleaf у порядку прямування, опускаючи стандартний синтаксис HTML або використані графічні стилі, і звертаючи увагу саме на розуміння механізму движка шаблонів.
<div th:fragment="notebook">
Операція "fragment" задає назву фрагмента та відкриває можливість використання вмісту блоку для команди "replace". Причому! У жодному разі не виключається множинне застосування в межах однієї сторінки, знову висуваючи аналогію з процедурами або функціями в мовах програмування.
<a th:href="@{'/sort/{sortDate}' (sortDate = 'ASC')}">
Використовується виклик анотації @PostMapping в Controller з мапінгом "/sort/{sortDate}", де {sortDate} - вихідний атрибут напряму сортування. Щось подібне можна спостерігати в наступному блоці, що додає динамічну зміну в залежності від положення обраного користувачем елемента в циклі ітерації:
<a th:href="@{'/edit/{id}'(id=${note.id})}">
<tr th:each="note : ${notes}">
Перелік значень дуже нагадує звичне використання блоку for у синтаксисі Java: змінна “note” приймає поточний елемент з масиву вхідного атрибуту ${notes} - масиву з сутностями, - і використовуються надалі зміни значень. Відвертим, можна відводити окрему статтю для перерахування широкого спектра можливостей Thymeleaf з наведенням прикладів практичного застосування - двигун шаблонів гранично простий і зовсім не вимагає вивчення великого багажу додаткового синтаксису. Описані вище функції викладено у технічній документації на офіційному сайті розробників і виконують ключове значення в організації зв'язку з back-end. Отже, можна впевнено переходити до наступної та завершальної частини. Звичайно ж,

Контролер, адміністратор у маленькій компанії

"Наріжний камінь в архітектурі web-додатку", - мабуть, жодним чином не вдасться підібрати точніший опис значущості компонента Controller в організації роботи програми: більшість операцій проводиться саме сполучним елементом між моделлю і виглядом. Завдяки механіці дії Spring Boot можна впевнено використовувати мапування та методи запиту GET/POST без жодних проблем, автоматично підключити репозиторій з даними. Створимо клас NoteController в окремому файлі в директорії “controllers”, знову звертаючись до застосування відповідної інструкції:
@Controller
public class NoteController {

   private NoteService service;

   @Autowired
   public void setNoteService(NoteService service) {
       this.service = service;
   }

   @GetMapping("/")
   public String list(Model model) {
       return "index";
   }
}
Уважний погляд може помітити важливу зміну в принципах побудови архітектури програми, пов'язану з додаванням сервісу для ізолювання бізнес-логіки від роботи зі службою управління базою даних. Виконані дії потрібні для збільшення універсальності готового продукту і надають широкий простір для зміни функціоналу інтерфейсу користувача без потреби змін у методах зв'язку з базою даних. Стандартне уявлення аж ніяк не виділяється із загальної маси подібних: інтерфейс розташований в окремій директорії і імплементується класом з інструкцією @Service для виявлення Spring Boot:
public interface NoteService {
   Note getNoteById(Integer id);
   void saveNote(Note note);
   void updateNote(Integer id, String message, boolean done);
   void deleteNote(Integer id);
   List<Note> findAll();
}

@Service
public class NoteServiceImpl implements NoteService{

   private NoteRepository repository;

   @Autowired
   public void setProductRepository(NoteRepository repository) {
       this.repository = repository;
   }

   @Override
   public Note getNoteById(Integer id) {
       return repository.findOne(id);
   }

   @Override
   public void saveNote(Note note) {
       repository.save(note);
   }

   @Override
   public void updateNote(Integer id, String message, boolean done) {
       Note updated = repository.findOne(id);
       updated.setDone(done);
       updated.setMessage(message);
       repository.save(updated);
   }

   @Override
   public void deleteNote(Integer id) {
       repository.delete(id);
   }

   @Override
   public List<Note> findAll() {
       return repository.findAll();
   }
}
Повернемося до огляду контролера та розберемо тонкощі організації роботи за допомогою методів Spring Boot. Анотація @Autowired повідомляє про потребу автоматичної прив'язки сервісу до зазначеної змінної відповідного типу та встановлює зв'язок із базою даних. Слід звернути більше уваги на спосіб спілкування з видом, позначений інструкцією @GetMapping("/") і повертає сторінку з ім'ям “index” при отриманні дзвінка localhost:8080. Можна використовувати різний підхід, конкретизуючи розширений опис @RequestMapping(value = "/", method = RequestMethod.GET) або замінити тип, що повертається на готову ModelAndView. Однак, згідно з поточним положенням досвіду практичного застосування, зовсім не помічаю кардинальних відмінностей в кінцевому результаті і використовую звичний варіант. Розширимо котролер методом додавання нових елементів за допомогою додаткової вкладки. Після натискання користувачем на елемент навігаційної панелі відбувається виклик @GetMapping("/new") та перенаправлення на сторінку "new" з директорії "operations", що повертає параметр з ім'ям "message" при підтвердженні введених даних використанням кнопки та виконує переадресаацію на головний блок. Окремої згадки вимагає потреба повного збігу найменування змінної у вікні введення з ім'ям значення, що передається. повертає параметр з ім'ям “message” під час підтвердження введених даних використанням кнопки та виконує переадресаацію на головний блок. Окремої згадки вимагає потреба повного збігу найменування змінної у вікні введення з ім'ям значення, що передається. повертає параметр з ім'ям “message” під час підтвердження введених даних використанням кнопки та виконує переадресаацію на головний блок. Окремої згадки вимагає потреба повного збігу найменування змінної у вікні введення з ім'ям значення, що передається.
<input type="text" class="form-control" id="message" th:name="message" placeholder="Enter your note." maxlength="100"/>
@GetMapping("/new")
public String newNote() {
   return "operations/new";
}

@PostMapping("/save")
public String updateNote(@RequestParam String message) {
   service.saveNote(new Note(message));
   return "redirect:/";
}
Така методика використовується оновлення записи. Після натискання на елемент керування відбувається виклик мапування @GetMapping("/edit/{id}") і передача ідентифікатора з url-рядка, додається атрибут "note" із записом для подальшого редагування. @RequestParam(value = "done", required = false) boolean done) вказівка ​​конкретного значення надає ключову роль у використанні checkbox при застосуванні движка шаблонів Thymeleaf і встановлюється за умовчанням положення "false".
@GetMapping("/edit/{id}")
public String edit(@PathVariable Integer id, Model model) {
   Note note = service.getNoteById(id);
   model.addAttribute("note", note);
   return "operations/edit";
}

@PostMapping("/update")
public String saveNote(@RequestParam Integer id, @RequestParam String message,
                      @RequestParam(value = "done", required = false) boolean done) {
   service.updateNote(id, message, done);
   return "redirect:/";
}
Видалення елементів з бази даних виконується гранично просто і абсолютно не вимагає видатних маніпуляцій, викликаючи відповідну функцію сервісу за допомогою переданого значення:
@GetMapping("/delete/{id}")
public String delete(@PathVariable Integer id) {
   service.deleteNote(id);
   return "redirect:/";
}
Тепер внесемо маленькі корективи в готові фрагменти та перейдемо до захоплюючого спілкування з MySQL за допомогою query-запитів у Spring Data JPA, окремо додаючи функцію керування простою фільтрацією перед закриттям Controller.
@Controller
public class NoteController {

   private String sortDateMethod = "ASC";

   @GetMapping("/")
   public String list(Model model) {
       List<Note> notebook = filterAndSort();
       model.addAttribute("notes", notebook);
       model.addAttribute("sort", sortDateMethod);
       return "index";
   }

private List<Note> filterAndSort() {
   List<Note> notebook = null;
   switch (sortDateMethod) {
       case "ASC":
           notebook = service.findAllByOrderByDateAsc();
           break;
       case "DESC":
           notebook = service.findAllByOrderByDateDesc();
           break;
   }
   return notebook;
}

Такий маленький, але такий важливий Query.

Незручно визнаватись, фільтрація значень всупереч очікуванням виявилася черговим каменем спотикання у виконанні технічного завдання, впевнено долаючи встановлений пагінацією - розбиттям масиву даних на окремі сторінки певної розмірності для подальшого відображення, - поріг складності. Швидше за все, давалася взнаки накопичена втома, але... осяяння зійшло після цілком випадкового зіткнення з Query-запитами.
public interface NoteRepository extends JpaRepository<Note, Integer> {
   List<Note> findAllByOrderByDateAsc();
   List<Note> findAllByOrderByDateDesc();
}
Spring Data JPA надає можливості для створення конкретизованих запитів до бази даних, що позбавляють потреби сортувати інформацію після отримання та володіють широким потенціалом для застосування. Наприклад:
List<Note> findAllByOrderByDateAsc();
Метод буде перетворений на SQL запит і відобразить всі записи (findAll) з сортуванням (byOrder) за датою (byDate) у порядку зростання (Asc). Більше того, можна складати складні комбінації та проводити вибірку за багатьма полями за єдину вимогу. Скажімо, вибрати всі (findAll) виконані (byDoneTrue) записи в порядку (byOrder) зменшення (Decs) за значенням дати (byDate):
Page<Note> findAllByDoneTrueOrderByDateDesc(Pageable pageable);

Висновок або чергова сповідь програміста-початківця

Всі! Можна сміливо запускати web-додаток за допомогою комбінації Shift+F10 або натисканням на відповідну іконку. Spring Boot збере програму на Apache Maven та встановить локальний сервер Apache Tomcat на адресау localhost:8080. Тепер достатньо лише перейти за посиланням у будь-якому браузері.
Завоювання Spring Boot - 6
І, звичайно, розробити методику для виконання інших бізнес-вимог. Потенціал програми обмежується докладеними зусиллями, винахідливою ініціативою та фантазією розробника.
Завоювання Spring Boot - 7
Будучи відвертим і звертаючи увагу на пройдений шлях, знову і знову переконуюсь у вірності обраного напряму та усвідомлюю користь від навчання на освітньому порталі JavaRush. Завдяки безлічі практичних завдань вдалося повернути принадний інтерес до вивчення програмування, остаточно забитий у застарілій і дивовижно нудній програмі вищого навчального закладу подібного напряму. Чотири місяці активного вивчення матеріалу у back-end стеку технологій вклали набагато більше знань у порівнянні з цілими роками відвідин лекцій та лабораторних занять. Хочете вірте, а хочете – ні. Бажаю не пасувати перед труднощами входження у складний матеріал, адже саме завдяки подоланню перешкод ми стаємо кращими та розвиваємось у професійному та особистісному плані. Сподіваюся, Невелика розповідь сприяла відкриттю свіжих ідеї для застосування чудового інструменту під назвою SpringBoot. PSGithub .
Коментарі
ЩОБ ПОДИВИТИСЯ ВСІ КОМЕНТАРІ АБО ЗАЛИШИТИ КОМЕНТАР,
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ