# თავი 1: შესავალი Spring-სა და Spring Boot-ში
---
## 1.1 Spring ეკოსისტემა
სანამ კოდის ერთ ხაზს მაინც დავწერთ, მნიშვნელოვანია გავიგოთ ის გარემო, რომელშიც ვიწყებთ მუშაობას. Spring არ არის მხოლოდ ერთი ბიბლიოთეკა ან ერთი ფრეიმვორქი — ის არის პროექტების მთელი ეკოსისტემა, რომელთაგან თითოეული შექმნილია Enterprise Java აპლიკაციების შექმნისას წარმოქმნილი კონკრეტული კლასის პრობლემების გადასაჭრელად. Spring-ში არსებობს პროექტები ვებ დეველოპმენტისთვის, მონაცემთა წვდომისთვის (data access), უსაფრთხოებისთვის, შეტყობინებებისთვის (messaging), პაკეტური დამუშავებისთვის (batch processing), ქლაუდ ინფრასტრუქტურისთვის და მრავალი სხვისთვის. ეს პროექტები მუდმივად ვითარდება: ისინი რეგულარულად იღებენ განახლებებს, უსაფრთხოების პატჩებს და ახალ შესაძლებლობებს, ხოლო დროთა განმავლობაში ეკოსისტემას სრულიად ახალი პროექტები ემატება.
ამ ეკოსისტემის გულში დგას თავად **Spring Framework** — ფუნდამენტური ბიბლიოთეკა, რომელიც უზრუნველყოფს დამოკიდებულებების ინექციას (dependency injection), ტრანზაქციების მართვას და პროგრამირების მოდელს Java აპლიკაციების ასაშენებლად. Spring-ის ყველა სხვა პროექტი მასზეა დაშენებული.
და აქვეა **Spring Boot**.
---
## 1.2 რა არის Spring Boot?
Spring Boot არის ერთ-ერთი ყველაზე ფართოდ გამოყენებადი პროექტი Spring ეკოსისტემაში. მისი მიზანი მარტივია: მაქსიმალურად გაამარტივოს Spring-ზე დაფუძნებული აპლიკაციების შექმნა და გაშვება.
ტრადიციული Spring აპლიკაციები დეველოპერისგან მოითხოვს დიდი რაოდენობით კონფიგურაციის დაწერას — XML ფაილები, Java კონფიგურაციის კლასები, servlet mapping-ები, დამოკიდებულებების ვერსიების მართვა და ა.შ. — სანამ რაიმე ბიზნეს ლოგიკის დაწერა გახდება შესაძლებელი. Spring Boot გამორიცხავს ამ რუტინის დიდ ნაწილს ფილოსოფიის დანერგვით, რომელიც ცნობილია როგორც **"კონვენცია კონფიგურაციის ნაცვლად" (convention over configuration).** იმის მაგივრად, რომ მოგთხოვოთ ყველა დეტალის მითითება, Spring Boot გაწვდით გონივრულ default პარამეტრებს. თუ რაიმეს შეცვლა გჭირდებათ, თქვენ აკეთებთ მხოლოდ ამ კონკრეტული დეტალის გადაფარვას. სხვა ყველაფერი რჩება თავის default მდგომარეობაში.
ამ ფილოსოფიის პრაქტიკული შედეგი მნიშვნელოვანია. Spring Boot-ის დახმარებით, დეველოპერი ფოკუსირდება აპლიკაციის კოდის წერაზე და არა ინფრასტრუქტურასა და კონფიგურაციასთან ბრძოლაზე.
---
## 1.3 Spring Boot ტრადიციული Spring-ის წინააღმდეგ
იმის დასაფასებლად, თუ რას გვაძლევს Spring Boot, სასარგებლოა იმის გაგება, თუ როგორი იყო ცხოვრება მის გარეშე.
ტრადიციულ Spring აპლიკაციაში, თქვენ ხელით მოგიწევდათ servlet კონტეინერის კონფიგურაცია, `DispatcherServlet`-ის განსაზღვრა `web.xml` ფაილში (ან მის Java-ზე დაფუძნებულ ეკვივალენტში), თითოეული bean-ისა და მისი დამოკიდებულებების გამოცხადება, ბიბლიოთეკის ვერსიების ხელით მართვა და მიღებული WAR ფაილის განთავსება გარე აპლიკაციის სერვერზე, როგორიცაა Apache Tomcat. თითოეული ეს ნაბიჯი მოითხოვდა დეველოპერისგან ექსპლიციტურ ყურადღებას.
Spring Boot ცვლის ამ სურათს ოთხი ფუნდამენტური გზით:
* **Auto-Configuration (ავტო-კონფიგურაცია).** როდესაც პროექტს ამატებთ ბიბლიოთეკას — მაგალითად, web starter-ს ან მონაცემთა ბაზის დრაივერს — Spring Boot აღმოაჩენს მას classpath-ზე და ავტომატურად აკონფიგურირებს საჭირო bean-ებსა და პარამეტრებს. თქვენ არ გჭირდებათ მისთვის იმის თქმა, რომ გსურთ ვებ სერვერი; ის ხედავს ვებ ბიბლიოთეკას და თავად აკონფიგურირებს მას თქვენთვის.
* **Embedded Server (ჩაშენებული სერვერი).** არ არის საჭირო გარე Tomcat ინსტანსის დაყენება და მართვა. Spring Boot აშენებს servlet კონტეინერს (default-ად Tomcat) პირდაპირ თქვენს აპლიკაციაში. როდესაც უშვებთ აპლიკაციას, სერვერიც მასთან ერთად ირთვება.
* **Starter Dependencies (სასტარტო დამოკიდებულებები).** იმის მაგივრად, რომ ეძებოთ ინდივიდუალური ბიბლიოთეკები და იდარდოთ თავსებად ვერსიებზე, Spring Boot გთავაზობთ კურირებულ "starter" პაკეტებს. მაგალითად, `spring-boot-starter-web` შემოიტანს ყველაფერს, რაც საჭიროა ვებ დეველოპმენტისთვის — Spring MVC, ჩაშენებული Tomcat სერვერი, JSON-ის დასამუშავებელი ბიბლიოთეკები — ისეთ ვერსიებში, რომლებიც გარანტირებულად მუშაობენ ერთად.
* **Opinionated Defaults (ფიქსირებული საწყისი პარამეტრები).** Spring Boot ირჩევს ისეთ default პარამეტრებს, რომლებიც თავიდანვე კარგად მუშაობს: სერვერი ეშვება 8080 პორტზე, შაბლონები (templates) იტვირთება კონკრეტული დირექტორიიდან, სტატიკური რესურსები მოემსახურება სხვა დირექტორიიდან. ამ პარამეტრების გადაფარვა ნებისმიერ დროს არის შესაძლებელი, მაგრამ ამის გაკეთება გიწევთ მხოლოდ მაშინ, როცა თქვენი მოთხოვნები განსხვავდება კონვენციისგან.
---
## 1.4 რა არის ახალი Spring Boot 4-ში
ეს კურსი იყენებს **Spring Boot 4**-ს, რომელიც გამოვიდა 2025 წლის ნოემბერში. ის დაშენებულია **Spring Framework 7**-ზე და წარმოადგენს პლატფორმის ახალ თაობას. მიუხედავად იმისა, რომ კონფიგურაციის ნაცვლად კონვენციის ძირითადი ფილოსოფია უცვლელი რჩება, არსებობს რამდენიმე მნიშვნელოვანი განახლება, რომელიც უნდა იცოდეთ:
* **Java 17 Baseline.** Spring Boot 4 მინიმუმ მოითხოვს Java 17-ს. რეკომენდებულია Java 21 ან 25 (ბოლო LTS გამოშვებები), რათა ისარგებლოთ უფრო ახალი JVM ფუნქციებით, როგორიცაა virtual threads, pattern matching და records.
* **Jakarta EE 11.** ფრეიმვორქმა დაასრულა მიგრაცია ძველი `javax.*` პაკეტებიდან `jakarta.*`-ზე. თუ წააწყდებით ძველ ტუტორიალებს ან დოკუმენტაციას, რომლებიც მიუთითებენ `javax.servlet` ან `javax.persistence`-ზე, იცოდეთ, რომ ისინი ჩანაცვლდა შესაბამისად `jakarta.servlet` და `jakarta.persistence`-ით.
* **Modularized Codebase (მოდულარიზებული კოდის ბაზა).** Spring Boot-ის კოდის ბაზა დაიყო უფრო მცირე, უფრო ფოკუსირებულ მოდულებად (jar-ებად). ეს იწვევს დამოკიდებულებების უფრო სუფთა ხეს (dependency tree) და აპლიკაციის უფრო მცირე ზომას.
* **Null Safety with JSpecify.** Spring Boot 4 იყენებს JSpecify ანოტაციებს მთელ პორტფოლიოში, რაც ეხმარება დეველოპერებს დაიჭირონ null-თან დაკავშირებული პოტენციური ბაგები კომპილაციის დროს.
ამ შესავალი თავისთვის, ეს ცვლილებები ძირითადად ფონურ რეჟიმში მუშაობს — Spring Boot-ის ავტო-კონფიგურაცია აგვარებს დეტალებს. თუმცა კარგია გარემოს ცოდნა, და ამ ფუნქციებს უფრო დეტალურად შევხვდებით კურსის მსვლელობისას.
---
## 1.5 პროექტის დაყენება Spring Initializr-ის გამოყენებით
ახალი Spring Boot პროექტის შესაქმნელად ყველაზე სწრაფი გზა არის **Spring Initializr**, ვებ-ზე დაფუძნებული ინსტრუმენტი, რომელსაც გთავაზობთ Spring გუნდი.
1. გადადით [https://start.spring.io](https://start.spring.io)-ზე.
2. დააკონფიგურირეთ პროექტის მეტამონაცემები:
* **Project:** Maven
* **Language:** Java
* **Spring Boot:** 4.0.x (აირჩიეთ უახლესი სტაბილური გამოშვება)
* **Group:** თქვენი ორგანიზაციის შებრუნებული დომენი (მაგ., `ge.tsu`)
* **Artifact:** თქვენი პროექტის სახელი (მაგ., `blog`)
* **Packaging:** Jar
* **Java:** 17 (ან 21/25, თუ ხელმისაწვდომია)
3. **Dependencies** სექციაში დაამატეთ შემდეგი:
* **Spring Web** — შეიცავს კომპონენტებს ვებ აპლიკაციების შესაქმნელად (Spring MVC, ჩაშენებული Tomcat და ა.შ.).
* **Apache Freemarker** — FreeMarker შაბლონების ძრავი (template engine), რომელსაც გამოვიყენებთ HTML გვერდების დასარენდერებლად.
* **Spring Boot DevTools** — დეველოპმენტის დროის ინსტრუმენტები, რომლებიც უზრუნველყოფენ ავტომატურ გადატვირთვას და ცოცხალ განახლებას (live reload).
* **Lombok** — ანოტაციების დამუშავების ბიბლიოთეკა, რომელიც ამცირებს boilerplate კოდს (getter-ები, setter-ები, კონსტრუქტორები და ა.შ.).
4. დააჭირეთ **Generate**. ჩამოიტვირთება ZIP არქივი.
5. ამოაარქივეთ არქივი და გახსენით პროექტი თქვენს IDE-ში (რეკომენდებულია IntelliJ IDEA).
6. გაუშვით `main(..)` მეთოდი გენერირებულ `*Application.java` კლასში.
თუ ყველაფერი სწორად არის დაყენებული, დაინახავთ ლოგის გამომავალ ინფორმაციას, რომელიც მთავრდება ხაზით, სადაც წერია, რომ აპლიკაცია ჩაირთო და უსმენს 8080 პორტს. გახსენით ბრაუზერი და გადადით `http://localhost:8080`-ზე — დაინახავთ სტანდარტულ შეცდომის გვერდს (რადგან ჯერ არ განგვისაზღვრავს რაიმე შიგთავსი), რაც ადასტურებს, რომ სერვერი მუშაობს.
---
## 1.6 პროექტის სტრუქტურის გაგება
ახლად გენერირებული Spring Boot პროექტი შეიცავს უამრავ ფაილსა და დირექტორიას. მათი უმეტესობა ემსახურება build სისტემას ან ტესტირების ინფრასტრუქტურას. ამჟამად, ყველაზე მნიშვნელოვანია:
| გზა | მიზანი |
| --- | --- |
| `src/main/java/.../BlogApplication.java` | მთავარი აპლიკაციის კლასი. ეს არის შესვლის წერტილი. |
| `src/main/resources/templates/` | FreeMarker შაბლონის ფაილები (`.ftlh`). |
| `src/main/resources/static/` | სტატიკური რესურსები — CSS, JavaScript, სურათები. |
| `src/main/resources/application.properties` | ცენტრალური კონფიგურაციის ფაილი. |
| `pom.xml` | Maven პროექტის კონფიგურაცია და დამოკიდებულებების დეკლარაციები. |
### `src/main/resources` დირექტორია
ეს დირექტორია იმსახურებს განსაკუთრებულ ყურადღებას, რადგან სწორედ აქ განთავსდება თითქმის ყველა ჩვენი არა-Java ფაილი.
**`/static/`** განკუთვნილია ფაილებისთვის, რომლებიც უნდა მიეწოდოს პირდაპირ ბრაუზერს ყოველგვარი დამუშავების გარეშე: სტილის ფაილები, JavaScript ფაილები, სურათები, ფონტები და ა.შ. როდესაც აპლიკაცია ირთვება, Spring Boot ამ დირექტორიის შიგთავსს ხელმისაწვდომს ხდის ძირეულ URL-ზე. მაგალითად, `/static/css/style.css`-ში მოთავსებული ფაილი ხელმისაწვდომი იქნება `http://localhost:8080/css/style.css` მისამართზე.
**`/templates/`** არის ადგილი, სადაც შაბლონების (templates) ფაილები ინახება. ჩვენს შემთხვევაში, ეს იქნება FreeMarker შაბლონები `.ftlh` გაფართოებით. სტატიკური ფაილებისგან განსხვავებით, შაბლონები მუშავდება template ძრავის მიერ, სანამ ბრაუზერს გაეგზავნება — სწორედ ეს ხდის მათ დინამიურს.
**`application.properties`** არის მთავარი კონფიგურაციის ფაილი. მისი მეშვეობით ჩვენ შეგვიძლია გადავფაროთ Spring Boot-ის ნებისმიერი კონვენციური default პარამეტრი. მაგალითად:
```properties
spring.application.name=blog
server.port=8080
server.servlet.context-path=/blog
```
პირველი ხაზი ჩვენს აპლიკაციას სახელს ანიჭებს. მეორე აყენებს პორტს (8080 არის default, ამიტომ ეს ხაზი ტექნიკურად ზედმეტია, მაგრამ ექსპლიციტურობამ შეიძლება გააუმჯობესოს კითხვადობა). მესამე აყენებს კონტექსტურ გზას (context path), რაც ნიშნავს, რომ აპლიკაცია ხელმისაწვდომი იქნება `http://localhost:8080/blog` მისამართზე root-ის ნაცვლად.
---
## 1.7 Maven და `pom.xml`
ჩვენი პროექტი იყენებს **Maven**-ს როგორც build ინსტრუმენტს. Maven მართავს დამოკიდებულებებს (გარე ბიბლიოთეკებს, რომლებიც ჩვენს პროექტს სჭირდება), აკომპილირებს საწყის კოდს, უშვებს ტესტებს და აპაკეტებს აპლიკაციას გაშვებად JAR ფაილად. ეს ყველაფერი კონფიგურირდება ერთი ფაილის მეშვეობით: `pom.xml`.
გენერირებული `pom.xml`-ის რამდენიმე ნაწილი განმარტებას იმსახურებს.
### Parent POM (მშობელი POM)
```xml
org.springframework.bootspring-boot-starter-parent4.0.1
```
ჩვენი პროექტის მშობლად `spring-boot-starter-parent`-ის გამოცხადებით, ჩვენ მემკვიდრეობით ვიღებთ დიდი რაოდენობით წინასწარ კონფიგურირებულ ქცევას: დამოკიდებულებების მართულ ვერსიებს (ასე რომ ჩვენ არ დაგვჭირდება ვერსიის ნომრების მითითება Spring-ის მიერ მართული ბიბლიოთეკებისთვის), Maven plugin-ების კონფიგურაციას, Java ვერსიის property-ს და სხვა გონივრულ default-ებს. ეს არის ერთ-ერთი მთავარი მექანიზმი, რაც Spring Boot პროექტებს ასეთ ლაკონურს ხდის.
თუ, რაიმე მიზეზით, თქვენს პროექტს უკვე აქვს სხვა parent POM და არ შეუძლია `spring-boot-starter-parent`-ის გამოყენება, შეგიძლიათ მიაღწიოთ ეკვივალენტურ დამოკიდებულებების მართვას BOM (Bill of Materials) იმპორტით:
```xml
org.springframework.bootspring-boot-dependencies4.0.1pomimport
```
### Dependencies (დამოკიდებულებები)
დამოკიდებულებები, რომლებიც ჩვენ ავირჩიეთ პროექტის დაყენების დროს, ჩნდება `` სექციაში:
```xml
org.springframework.bootspring-boot-starter-weborg.springframework.bootspring-boot-starter-freemarkerorg.springframework.bootspring-boot-devtoolsruntimetrueorg.projectlomboklomboktrue
```
შეამჩნიეთ, რომ არცერთი ეს დამოკიდებულება არ აკონკრეტებს ვერსიის ნომერს. ვერსიები მემკვიდრეობით მიიღება parent POM-დან, რაც უზრუნველყოფს, რომ ყველა ბიბლიოთეკა თავსებადია ერთმანეთთან.
### Spring Boot Maven Plugin
```xml
org.springframework.bootspring-boot-maven-plugin
```
ეს პლაგინი პასუხისმგებელია რამდენიმე მნიშვნელოვან ამოცანაზე: მას შეუძლია გაუშვას აპლიკაცია პირდაპირ ბრძანებათა სტრიქონიდან `mvn spring-boot:run`-ის მეშვეობით, ის ქმნის გაშვებად JAR ფაილებს (ეგრეთ წოდებულ "fat JAR-ებს", რომლებიც აერთიანებს ყველა დამოკიდებულებას) `mvn package`-ის მეშვეობით და მხარს უჭერს ahead-of-time კომპილაციის ფუნქციებს, რომლებიც დაინერგა Spring Boot-ის ბოლო ვერსიებში.
---
## 1.8 `@SpringBootApplication` ანოტაცია და ავტო-კონფიგურაცია
ყველა Spring Boot პროექტს აქვს მთავარი კლასი, რომელიც ემსახურება როგორც შესვლის წერტილს. ის ასე გამოიყურება:
```java
@SpringBootApplication
public class BlogApplication {
public static void main(String[] args) {
SpringApplication.run(BlogApplication.class, args);
}
}
```
`@SpringBootApplication` ანოტაცია მაცდურად მარტივია. მის უკან სამი რამ ხდება:
1. **Component Scanning** (`@ComponentScan`) — Spring ამოწმებს ამ კლასის პაკეტს (და მის ყველა ქვე-პაკეტს) კლასებზე, რომლებიც ანოტირებულია `@Controller`, `@Service`, `@Repository`, `@Configuration` და სხვა სტერეოტიპებით. ის არეგისტრირებს ამ კლასებს როგორც bean-ებს აპლიკაციის კონტექსტში.
2. **Auto-Configuration** (`@EnableAutoConfiguration`) — Spring Boot ამოწმებს classpath-ს რათა დაადგინოს რა ბიბლიოთეკებია წარმოდგენილი და შესაბამისად აკონფიგურირებს აპლიკაციას. რადგან `spring-boot-starter-web` არის classpath-ზე, ის ავტომატურად აყენებს ჩაშენებულ Tomcat სერვერს, `DispatcherServlet`-ს და Spring MVC-ის სტანდარტულ პარამეტრებს. რადგან `spring-boot-starter-freemarker` წარმოდგენილია, ის აკონფიგურირებს FreeMarker template ძრავს თავისი default პარამეტრებით (შაბლონები `/templates/`-ში, სუფიქსი `.ftlh`, caching ჩართულია production-ში).
3. **Configuration** (`@Configuration`) — თავად კლასი არის Spring კონფიგურაციის კლასი, რაც ნიშნავს რომ მას შეუძლია შეიცავდეს `@Bean` მეთოდებს საჭიროების შემთხვევაში.
### საიდან იცის Spring Boot-მა რა უნდა დააკონფიგურიროს?
Spring Boot მოყვება ავტო-კონფიგურაციის კლასების დიდ კოლექციას, რომელთაგან თითოეული პასუხისმგებელია ერთი კონკრეტული ფუნქციის ან ინტეგრაციის კონფიგურაციაზე. როდესაც აპლიკაცია ირთვება, Spring Boot აფასებს პირობებს თითოეულ ამ კლასზე — მაგალითად, "არის თუ არა ეს ბიბლიოთეკა classpath-ზე?" ან "უკვე განსაზღვრა თუ არა დეველოპერმა ეს bean?" — და ააქტიურებს მხოლოდ იმ კონფიგურაციებს, რომლებიც შეესაბამება.
ეს მექანიზმი არის ის, რაც საშუალებას აძლევს Spring Boot-ს იგრძნობოდეს "მაგიურად", მაგრამ დარჩეს სრულად გამჭვირვალე. თუ ოდესმე დაგჭირდებათ ზუსტად იმის დანახვა, თუ რა დაკონფიგურირდა ავტომატურად (და რა არა), შეგიძლიათ დაამატოთ `--debug` გაშვების არგუმენტებში ან დააყენოთ `debug=true` `application.properties`-ში.
### ავტო-კონფიგურაციის მორგება (Customization)
ავტო-კონფიგურებული ქცევის მორგების ორი გავრცელებული გზა არსებობს.
შეგიძლიათ **გადაფაროთ property-ები** `application.properties`-ში:
```properties
server.port=9090
spring.freemarker.suffix=.ftlh
spring.freemarker.cache=false
```
ან შეგიძლიათ მთლიანად **გამორიცხოთ კონკრეტული ავტო-კონფიგურაციები**:
```java
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
public class BlogApplication { ... }
```
`exclude` ატრიბუტი სასარგებლოა, როდესაც Spring Boot აღმოაჩენს ბიბლიოთეკას, რომელიც გაქვთ classpath-ზე, მაგრამ რეალურად არ გსურთ მისი ავტო-კონფიგურაცია.
---
## 1.9 Live Reload-ის ჩართვა DevTools-ით
`spring-boot-devtools` დამოკიდებულება, რომელიც დავამატეთ პროექტის დაყენების დროს, არსებობს მხოლოდ დეველოპმენტის გამოცდილების გასაუმჯობესებლად. მისი მთავარი მახასიათებლებია:
* **Automatic Restart (ავტომატური გადატვირთვა).** როდესაც ცვლით Java კლასს და ინახავთ ფაილს, DevTools აღმოაჩენს ცვლილებას და ავტომატურად გადატვირთავს აპლიკაციას. ეს გადატვირთვა უფრო სწრაფია ვიდრე ცივი სტარტი, რადგან DevTools იყენებს ორ classloader-ს — ერთს თქვენი კოდისთვის (რომელიც ხელახლა იტვირთება) და მეორეს მესამე მხარის (third-party) ბიბლიოთეკებისთვის (რომელიც არ იტვირთება ხელახლა).
* **LiveReload.** DevTools მოიცავს LiveReload სერვერს. LiveReload ბრაუზერის ექსტენციასთან ერთად, შაბლონში, სტილის ფაილში ან სხვა რესურსში შეტანილი ნებისმიერი ცვლილება იწვევს ბრაუზერის ავტომატურ განახლებას.
* **Development-Friendly Defaults.** გარკვეული property-ები მორგებულია დეველოპმენტისთვის. მაგალითად, template caching გამორთულია, რათა `.ftlh` ფაილებში ცვლილებები დაუყოვნებლივ იყოს ხილული აპლიკაციის გადატვირთვის გარეშე.
მნიშვნელოვანი დეტალი: DevTools ავტომატურად გამორთულია, როდესაც აპლიკაცია ეშვება როგორც შეფუთული JAR (ანუ, production-ში). `runtime` და `true` მარკერები `pom.xml`-ში უზრუნველყოფენ, რომ ის არ გაჟონოს დამოკიდებულ პროექტებში ან production build-ებში.
---
## 1.10 სტატიკური კონტენტის მიწოდება
ყველაზე მარტივი სახის ვებსაიტი არის სტატიკური — ყველა მომხმარებელი ხედავს ზუსტად ერთსა და იმავე კონტენტს და სერვერის მხარეს გამოთვლები არ არის ჩართული. Spring Boot ტრივიალურს ხდის სტატიკური კონტენტის მიწოდებას.
ნებისმიერი ფაილი, რომელიც მოთავსებულია `src/main/resources/static/`-ში ავტომატურად მიეწოდება შესაბამის URL გზაზე. მაგალითად:
```text
src/main/resources/static/index.html → http://localhost:8080/index.html
src/main/resources/static/css/style.css → http://localhost:8080/css/style.css
src/main/resources/static/images/logo.png → http://localhost:8080/images/logo.png
```
Spring Boot მხარს უჭერს სტატიკური რესურსების ოთხ classpath ლოკაციას: `/static`, `/public`, `/resources`, და `/META-INF/resources`. ამ კურსში ჩვენ გამოვიყენებთ ექსკლუზიურად `/static`-ს, თანმიმდევრულობისთვის.
წმინდად სტატიკურ ვებსაიტს, თუმცა, აქვს მნიშვნელოვანი შეზღუდვა: ნებისმიერი ელემენტი, რომელიც გამოჩნდება ყველა გვერდზე — ნავიგაციის ზოლი, სათაური (header), ძირი (footer) — დუბლირებული უნდა იყოს ყველა HTML ფაილში. თუ გსურთ ნავიგაციის შეცვლა, უნდა დაარედაქტიროთ ყველა გვერდი. სწორედ აქ ხდება template ძრავი ღირებული.
---
## 1.11 შესავალი FreeMarker-ში
**Apache FreeMarker** არის template ძრავი Java პლატფორმისთვის. იღებს შაბლონის ფაილს — HTML დოკუმენტს ჩაშენებული FreeMarker დირექტივებით — და აერთიანებს მას აპლიკაციის მიერ მოწოდებულ მონაცემებთან, რათა აწარმოოს საბოლოო HTML, რომელიც იგზავნება ბრაუზერში. FreeMarker შაბლონები იწერება **FreeMarker Template Language (FTL)**-ზე, ლაკონურ ენაზე, რომელსაც აქვს ცვლადების, პირობითი ოპერატორების (conditionals), ციკლების, მაკროების და სხვათა მხარდაჭერა.
Spring Boot ავტომატურად აკონფიგურირებს FreeMarker-ს, როდესაც პოულობს `spring-boot-starter-freemarker`-ს classpath-ზე. default პარამეტრები, რომლებსაც ის იყენებს არის:
* შაბლონები იტვირთება `src/main/resources/templates/`-დან.
* მოსალოდნელი ფაილის გაფართოებაა `.ftlh` (რაც რთავს ავტომატურ HTML escaping-ს — უსაფრთხოების ფუნქცია, რომელიც იცავს XSS შეტევებისგან სპეციალური სიმბოლოების დაფარვით (escaping)).
* production-ში, შაბლონები ინახება ქეშში წარმადობისთვის. DevTools-ის აქტიურობისას, caching გამორთულია.
ამ ავტო-კონფიგურაციის გამო, ძალიან ცოტა რამის გაკეთება გვჭირდება FreeMarker-ის გამოსაყენებლად. ჩვენ ვათავსებთ `.ftlh` ფაილებს templates დირექტორიაში, და დანარჩენს Spring Boot აგვარებს.
### FTL სინტაქსი მოკლედ
FreeMarker შაბლონებში იყენებს ორი სახის სპეციალურ სინტაქსს:
**Interpolations (ინტერპოლაციები)** — `${expression}` — გამოიყენება მნიშვნელობების გამოსატანად. მაგალითად, `${title}` გამოიტანს ცვლადის მნიშვნელობას, რომელსაც ჰქვია `title`.
**Directives (დირექტივები)** — `<#directiveName ...>` — არის ინსტრუქციები template ძრავისთვის. ისინი აკონტროლებენ შაბლონის ლოგიკასა და სტრუქტურას. გავრცელებული დირექტივები მოიცავს `<#if>`, `<#list>`, `<#assign>`, `<#macro>`, `<#import>`, და `<#include>`.
კომენტარები იწერება როგორც `<#-- ეს არის კომენტარი -->` და არ ხვდება გამომავალ შედეგში.
---
## 1.12 სტატიკური საიტიდან FreeMarker შაბლონებამდე
მოდით განვიხილოთ სტატიკური ვებსაიტის იმგვარად გარდაქმნის პროცესი, რომ გამოიყენოს FreeMarker შაბლონები, რითაც გზად დუბლირებას აღმოვფხვრით.
### ნაბიჯი 1: HTML ფაილების გადატანა `/templates/`-ში
ფაილები, რომლებიც უნდა დამუშავდეს FreeMarker-ის მიერ, უნდა მოთავსდეს `src/main/resources/templates/`-ში და მიენიჭოს `.ftlh` გაფართოება. სტატიკური რესურსები (CSS, JS, სურათები) რჩება `/static/`-ში.
```text
src/main/resources/
├── static/
│ ├── css/
│ │ └── style.css
│ └── images/
│ └── logo.png
└── templates/
├── index.ftlh
├── about.ftlh
├── posts.ftlh
└── contact.ftlh
```
### ნაბიჯი 2: URL-ების დამაკავშირება შაბლონებთან
ჩვენ უნდა ვუთხრათ Spring Boot-ს, რომელი შაბლონი დაარენდეროს თითოეული URL-სთვის. მარტივი გვერდებისთვის, რომლებიც არ საჭიროებენ სერვერიდან რაიმე დინამიურ მონაცემებს, შეგვიძლია გამოვიყენოთ **View Controllers** — მსუბუქი მექანიზმი, რომელიც აკავშირებს URL-ს პირდაპირ შაბლონის სახელთან სრული controller კლასის დაწერის გარეშე.
```java
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("index");
registry.addViewController("/about").setViewName("about");
registry.addViewController("/posts").setViewName("posts");
registry.addViewController("/contact").setViewName("contact");
}
}
```
`@Configuration` ანოტაცია ეუბნება Spring-ს, რომ ეს კლასი შეიცავს კონფიგურაციას. `WebMvcConfigurer`-ის იმპლემენტაციით და `addViewControllers(..)`-ის გადაფარვით, ჩვენ ვარეგისტრირებთ URL-დან-შაბლონზე mapping-ებს. როდესაც მომხმარებელი ეწვევა `/about`-ს, Spring-ის `DispatcherServlet` ხსნის view-ს სახელს `"about"`, უკავშირებს ფაილს `templates/about.ftlh`, ატარებს მას FreeMarker-ში და აბრუნებს შედეგს.
შენიშვნა: `@Configuration` ანოტაცია აუცილებელია. მის გარეშე, Spring ვერ იცნობს ამ კლასს და view controller-ები არ დარეგისტრირდება.
### ნაბიჯი 3: დუბლირების აღმოფხვრა მაკროებით
ამ ეტაპზე, თითოეული `.ftlh` ფაილი არის სრული HTML დოკუმენტი. ეს ნიშნავს, რომ `` სექცია, ნავიგაციის ზოლი და footer დუბლირებულია ყველა გვერდზე. ნავიგაციის შეცვლის შემთხვევაში, მოგვიწევს ყველა ფაილის რედაქტირება.
FreeMarker ამ პრობლემას წყვეტს **მაკროებით (macros)**. მაკრო არის მრავალჯერადი გამოყენების შაბლონის ფრაგმენტი, რომელსაც შეუძლია მიიღოს პარამეტრები და დაარენდეროს ბუდებული (nested) კონტენტი. ჩვენ შევქმნით **layout (განლაგების) მაკროს** — ერთ მაკროს, რომელიც განსაზღვრავს გვერდის მთლიან სტრუქტურას, ადგილის მითითებით, სადაც ჩაისმება თითოეული გვერდის უნიკალური შიგთავსი.
#### Layout მაკროს განსაზღვრა
შექმენით ფაილი სახელად `layout.ftlh` templates დირექტორიაში:
```html
<#macro page title="My Blog">
${title}
<#nested>
#macro>
```
აქ მთავარი ელემენტებია:
* `<#macro page title="My Blog">` აცხადებს მაკროს სახელად `page` პარამეტრით `title`, რომელსაც აქვს default მნიშვნელობა.
* `<#nested>` არის სპეციალური დირექტივა, რომელიც არენდერებს იმ შიგთავსს, რასაც გამომძახებელი შაბლონი აწვდის მაკროს გამხსნელ და დამხურავ ტეგებს შორის.
* `#macro>` ასრულებს მაკროს განსაზღვრას.
#### Layout მაკროს გამოყენება
თითოეული გვერდის შაბლონი ახლა დრამატულად გამარტივდა. აი `index.ftlh`:
```html
<#import "layout.ftlh" as layout>
<@layout.page title="Home">
Welcome to My Blog
This is the home page of our blog application.
@layout.page>
```
და `about.ftlh`:
```html
<#import "layout.ftlh" as layout>
<@layout.page title="About Us">
About
Learn more about who we are and what we do.
@layout.page>
```
`<#import "layout.ftlh" as layout>` დირექტივა ტვირთავს layout ფაილს და ხდის მის მაკროებს ხელმისაწვდომს `layout` სახელების სივრცის (namespace) ქვეშ. `<@layout.page>` ტეგი იძახებს `page` მაკროს, გადასცემს სათაურს და აწვდის გვერდის უნიკალურ კონტენტს, როგორც ბუდებულ (nested) ტანს.
ეს პატერნი — layout მაკრო `<#nested>` ადგილსამყოფელით — არის FreeMarker-ის ეკვივალენტი template inheritance-ისა, რომელსაც სხვა ძრავები იყენებენ. ახლა ყველა გვერდს აქვს თანმიმდევრული სტრუქტურა და სათაურში, footer-ში ან ნავიგაციაში ნებისმიერი ცვლილება მხოლოდ ერთ ადგილას არის საჭირო.
---
## 1.13 Spring-ის ჩაშენებული FreeMarker მაკროები
Spring Framework-ს მოყვება ჩაშენებული FreeMarker მაკროების ნაკრები, რომლებიც განსაზღვრულია ფაილში `spring.ftl`. ეს მაკროები უზრუნველყოფენ მოსახერხებელ ინტეგრაციას FreeMarker-სა და Spring MVC-ს შორის — განსაკუთრებით ფორმების მართვისთვის და კონტექსტის მცოდნე URL-ების გენერირებისთვის.
ამ მაკროების გამოსაყენებლად, თქვენ აიმპორტებთ `spring.ftl`-ს ნებისმიერი შაბლონის ზედა ნაწილში (ან, უფრო ხშირად, თქვენი layout შაბლონის შიგნით):
```html
<#import "/spring.ftl" as spring>
```
### `@spring.url` მაკრო
ერთ-ერთი ყველაზე მყისიერად გამოსადეგი მაკროა `@spring.url`. ის აგენერირებს URL-ებს, რომლებმაც იციან თქვენი აპლიკაციის კონტექსტური გზა (context path). ეს მნიშვნელოვანია, როდესაც თქვენი აპლიკაცია განთავსებულია `/`-ისგან განსხვავებული კონტექსტური გზის ქვეშ.
მაგალითად, თუ თქვენი `application.properties` შეიცავს:
```properties
server.servlet.context-path=/blog
```
მაშინ უბრალო HTML ბმული როგორიცაა `` გაფუჭდება, რადგან ის არ ითვალისწინებს `/blog` პრეფიქსს. `@spring.url` მაკრო წყვეტს ამას:
```html
Home
```
თუ კონტექსტური გზა არის `/blog`, ესენი აწარმოებენ შესაბამისად `/blog/css/style.css`, `/blog/`, და `/blog/images/logo.png`. თუ კონტექსტური გზა არ არსებობს, ისინი აწარმოებენ `/css/style.css`, `/`, და `/images/logo.png`. ეს ხდის თქვენს შაბლონებს პორტატიულს, მიუხედავად იმისა, თუ როგორ არის აპლიკაცია განთავსებული.
ჩვენ გამოვიკვლევთ სხვა Spring მაკროებს (განსაკუთრებით ფორმასთან დაკავშირებულებს, როგორიცაა `@spring.formInput`, `@spring.formSingleSelect`, და `@spring.showErrors`) შემდგომ თავებში, როდესაც დავიწყებთ ფორმების აშენებას და მომხმარებლის შეყვანილი მონაცემების დამუშავებას.
---
## 1.14 პირობითი რენდერინგი (Conditional Rendering) `<#if>`-ით
გვერდის ყველა ნაწილი არ უნდა დარენდერდეს ყოველ ჯერზე. ზოგჯერ სექცია უნდა გამოჩნდეს მხოლოდ მაშინ, როცა კონკრეტული მონაცემები არსებობს, ან ელემენტი უნდა შეიცვალოს პირობის საფუძველზე. FreeMarker ამას უმკლავდება `<#if>` დირექტივით.
ძირითადი ფორმა მარტივია:
```html
<#if condition>
... რენდერდება მხოლოდ მაშინ, როცა პირობა ჭეშმარიტია ...
#if>
```
თქვენ შეგიძლიათ დაამატოთ ალტერნატიული განშტოებები `<#elseif>` და `<#else>` გამოყენებით:
```html
<#if user??>
Welcome back, ${user.name}!
<#else>
Welcome, guest.
#if>
```
`??` ოპერატორი არის FreeMarker-ის **ჩაშენებული ტესტი (built-in test)**, რომელიც ამოწმებს არსებობს თუ არა ცვლადი (არ არის null). ეს არის ერთ-ერთი ყველაზე ხშირად გამოყენებადი ტესტი, რადგან შაბლონის მონაცემები ხშირად მოდის სერვერიდან და მნიშვნელობა შეიძლება იყოს ან არ იყოს მოდელში.
კიდევ ერთი ხშირად გამოყენებადი ტესტი არის `?has_content`, რომელიც კიდევ უფრო შორს მიდის: ის ამოწმებს, რომ მნიშვნელობა არსებობს **და** არ არის ცარიელი. სტრიქონებისთვის (strings), ეს ნიშნავს რომ სტრიქონი არ არის null და არ არის `""`. კოლექციებისთვის, ეს ნიშნავს რომ კოლექცია არ არის null და არ არის ცარიელი. ამ განსხვავებას მნიშვნელობა აქვს — ცვლადი შეიძლება არსებობდეს, მაგრამ ინახავდეს ცარიელ სტრიქონს და ხშირად გსურთ მას ისევე მოექცეთ, როგორც არარსებულს.
```html
<#if subtitle?has_content>
${subtitle}
#if>
```
აქ, `
` ტეგი რენდერდება მხოლოდ იმ შემთხვევაში, თუ `subtitle` არის განსაზღვრულიც და არაცარიელიც. თუ ის არის null ან `""`, მთელი ბლოკი გამოტოვებული იქნება.
### `<#if>`-ის კომბინირება მაკროებთან
პირობითი რენდერინგის ნამდვილი ძალა თვალსაჩინო ხდება მაკროების შიგნით. განვიხილოთ ბლოგის აპლიკაცია, სადაც გვინდა მრავალჯერადი გამოყენების **სტატიის პრევიუს (article preview)** კომპონენტი. ზოგ პოსტს აქვს მთავარი სურათი, ზოგს კი არა. მაკრომ უნდა დაარენდეროს სურათის სექცია მხოლოდ მაშინ, როდესაც სურათის URL არის მოწოდებული:
```html
<#macro article title url imageUrl="">
<#if imageUrl?has_content>
#if>
<#nested>Read more »
#macro>
```
ამ მაკროში რამდენიმე რამ არის შესამჩნევი:
`imageUrl` პარამეტრს აქვს default მნიშვნელობა `""` (ცარიელი სტრიქონი). ეს ნიშნავს, რომ გამომძახებელს შეუძლია საერთოდ გამოტოვოს ის და მაკრო არ გაფუჭდება — `<#if imageUrl?has_content>` ტესტი უბრალოდ შეფასდება როგორც false და სურათის სექცია გამოტოვებული იქნება.
`<#nested>` დირექტივა ჩნდება კონტენტის სექციის შიგნით, რაც საშუალებას აძლევს თითოეულ გამომძახებელს მიაწოდოს მოკლე ამონარიდი ან შეჯამება, როგორც მაკროს ტანი.
აი როგორ შეიძლება ამ მაკროს გამოყენება პოსტების გვერდზე:
```html
<#import "components.ftlh" as ui>
<@ui.article title="Getting Started with Spring Boot"
url="/posts/spring-boot-intro"
imageUrl="/images/spring-boot.png">
Spring Boot makes it easy to create stand-alone, production-grade applications...
@ui.article>
<@ui.article title="Understanding FreeMarker Templates"
url="/posts/freemarker-templates">
FreeMarker is a powerful template engine for the Java platform...
@ui.article>
```
პირველი სტატია რენდერდება სურათით. მეორე ტოვებს `imageUrl` პარამეტრს, ამიტომ სურათის სექცია არ ჩნდება — მხოლოდ სათაური, ამონარიდი და "Read more" ბმული. ორივე იყენებს ერთსა და იმავე მაკროს.
---
## 1.15 მრავალჯერადი გამოყენების კომპონენტების მაკროები
ზემოთ მოყვანილი სტატიის მაკრო არის უფრო ფართო პატერნის ერთი მაგალითი: **კომპონენტების მაკროები**. ნებისმიერი მრავალჯერადი HTML პატერნი — შეტყობინების ყუთი (alert box), ბარათი (card), ნავიგაციის ერთეული, ფორმის ჯგუფი — არის მაკროდ ამოღების კანდიდატი.
მაგალითად, მარტივი alert კომპონენტი:
```html
<#macro alert type="info" message="">
${message}
#macro>
```
გამოყენებული გვერდზე:
```html
<@alert type="success" message="Your post has been published!" />
<@alert type="error" message="Something went wrong. Please try again." />
```
უკეთესი ორგანიზებისთვის, მოათავსეთ გაზიარებული მაკროები სპეციალურ ფაილში — ვთქვათ, `components.ftlh` — და დააიმპორტეთ იქ, სადაც საჭიროა:
```html
<#import "components.ftlh" as ui>
<@ui.alert type="success" message="Saved successfully." />
<@ui.article title="My First Post" url="/posts/first">
A short preview of the post content...
@ui.article>
```
ეს პატერნი ინარჩუნებს თქვენს შაბლონებს სუფთად და კომპონენტებს მრავალჯერადად გამოსაყენებელს. როგორც კი თქვენი აპლიკაცია იზრდება, `components.ftlh` ფაილი (ან ასეთი ფაილების ნაკრები, ორგანიზებული დანიშნულების მიხედვით) ხდება UI-ს საშენი ბლოკების ბიბლიოთეკა, საიდანაც ნებისმიერ გვერდს შეუძლია ამოღება.
---
## შეჯამება
ამ თავში ჩვენ დავფარეთ ფუნდამენტური კონცეფციები, რომლებიც საჭიროა Spring Boot 4-ითა და FreeMarker-ით ვებ აპლიკაციების შენების დასაწყებად:
* **Spring ეკოსისტემა** არის პროექტების კოლექცია Enterprise Java დეველოპმენტისთვის. **Spring Boot** ამარტივებს Spring-თან მუშაობას კონვენცია კონფიგურაციის ნაცვლად მიდგომის, ავტო-კონფიგურაციის, ჩაშენებული სერვერების და starter დამოკიდებულებების მეშვეობით.
* **Spring Boot 4** მოითხოვს Java 17+, დაშენებულია Spring Framework 7-ზე და მიზნად ისახავს Jakarta EE 11-ს.
* **Spring Initializr** არის რეკომენდებული გზა ახალი პროექტის გენერირებისთვის. ჩვენი პროექტი იყენებს ოთხ starter-ს: `spring-boot-starter-web`, `spring-boot-starter-freemarker`, `spring-boot-devtools`, და `lombok`.
* **პროექტის სტრუქტურა** აცალკევებს შაბლონებს (`/templates/`-ში), სტატიკურ რესურსებს (`/static/`-ში), კონფიგურაციას (`application.properties`-ში), და build მეტამონაცემებს (`pom.xml`-ში).
* **`@SpringBootApplication`** ანოტაცია იწვევს component scanning-ს, ავტო-კონფიგურაციას და აღნიშნავს კლასს როგორც კონფიგურაციის წყაროს. ავტო-კონფიგურაცია აღმოაჩენს classpath ბიბლიოთეკებს და შესაბამისად აკონფიგურირებს bean-ებს.
* **DevTools** უზრუნველყოფს ავტომატურ გადატვირთვებს, LiveReload-ს და დეველოპმენტისთვის მორგებულ default პარამეტრებს. ის ავტომატურად გამორთულია production-ში.
* **სტატიკური კონტენტი** მიეწოდება `/static/` დირექტორიიდან დამუშავების გარეშე.
* **FreeMarker** არის ჩვენი template ძრავი. შაბლონები იყენებენ `.ftlh` გაფართოებას (HTML ავტო-escaping-ისთვის), მოთავსებულია `/templates/`-ში და იწერება FreeMarker Template Language (FTL)-ზე.
* **მაკროები** — განსაკუთრებით layout მაკროს პატერნი `<#nested>`-ით — აღმოფხვრის HTML დუბლირებას მრავალჯერადი გვერდის სტრუქტურის განსაზღვრით.
* **Spring-ის ჩაშენებული მაკროები** (დაიმპორტებული `/spring.ftl`-ის მეშვეობით) უზრუნველყოფენ კონტექსტის მცოდნე URL-ების გენერირებას `@spring.url`-ით და ფორმების მართვის უტილიტებით, რომლებსაც მომავალ თავებში გამოვიყენებთ.
* **პირობითი რენდერინგი** `<#if>`-ით, კომბინირებული ჩაშენებულ ტესტებთან როგორიცაა `??` (არსებობს) და `?has_content` (არსებობს და არაცარიელია), საშუალებას აძლევს შაბლონებს მოარგონ თავიანთი გამომავალი შედეგი მიღებული მონაცემების საფუძველზე.
* **კომპონენტების მაკროები** — როგორიცაა სტატიის პრევიუს მაკრო — აერთიანებს მრავალჯერად UI პატერნებს, რაც შაბლონებს სუფთად და მარტივად მოსავლელად ინარჩუნებს აპლიკაციის ზრდასთან ერთად.
---
## რესურსები
* [Spring Framework-ის მიმოხილვა](https://spring.io/projects/spring-framework)
* [Spring Boot დოკუმენტაცია](https://docs.spring.io/spring-boot/index.html)
* [Spring Boot 4.0 Release Notes](https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-4.0-Release-Notes)
* [Spring Initializr](https://start.spring.io)
* [Apache FreeMarker სახელმძღვანელო](https://freemarker.apache.org/docs/index.html)
* [FreeMarker Template Language ცნობარი](https://freemarker.apache.org/docs/ref.html)
* [Spring MVC FreeMarker ინტეგრაცია](https://docs.spring.io/spring-framework/reference/web/webmvc-view/mvc-freemarker.html)
* [Spring Web MVC დოკუმენტაცია](https://docs.spring.io/spring-framework/reference/web/webmvc.html)
* [View Controllers დოკუმენტაცია](https://docs.spring.io/spring-framework/reference/web/webmvc/mvc-config/view-controller.html)
---
## პრაქტიკული დავალება: ააშენეთ სტატიკური ბლოგის ვებსაიტი
თქვენი დავალებაა შექმნათ სტატიკური ბლოგის ვებსაიტი Spring Boot 4-ისა და FreeMarker-ის გამოყენებით.
**მოთხოვნები:**
1. **შექმენით ახალი Spring Boot პროექტი** Spring Initializr-ის გამოყენებით 1.5 სექციაში ჩამოთვლილი დამოკიდებულებებით.
2. **შექმენით მინიმუმ ოთხი გვერდი** — მაგალითად: მთავარი გვერდი (`index.ftlh`), ჩვენ შესახებ გვერდი (`about.ftlh`), პოსტების გვერდი (`posts.ftlh`) და კონტაქტის გვერდი (`contact.ftlh`). შეიტანეთ ნებისმიერი კონტენტი, რაც მოგესურვებათ; ფოკუსი სტრუქტურაზეა და არა კონტენტზე.
3. **შექმენით layout მაკრო** სპეციალურ ფაილში (მაგ., `layout.ftlh`), რომელიც განსაზღვრავს HTML დოკუმენტის სრულ სტრუქტურას — ``, ``, ნავიგაციას, `<#nested>` ადგილსამყოფელს გვერდის კონტენტისთვის და footer-ს. თითოეული გვერდის შაბლონმა უნდა გამოიყენოს ეს მაკრო დოკუმენტის სტრუქტურის დუბლირების ნაცვლად.
4. **გამოიყენეთ `@spring.url**` ყველა ბმულისა და რესურსის მისამართისთვის თქვენს შაბლონებში (CSS ფაილები, ნავიგაციის ბმულები, სურათები). დააყენეთ მორგებული `server.servlet.context-path` `application.properties`-ში და გადაამოწმეთ, რომ ყველა URL სწორად მუშაობს კონტექსტური გზით.
5. **შექმენით კონფიგურაციის კლასი**, რომელიც ანოტირებულია `@Configuration`-ით, აკეთებს `WebMvcConfigurer`-ის იმპლემენტაციას და არეგისტრირებს view controller-ებს თითოეული თქვენი გვერდისთვის.
6. **დაამატეთ მინიმუმ ერთი CSS სტილის ფაილი** `/static/css/`-ში და დააკავშირეთ ის თქვენი layout მაკროს მეშვეობით.
7. **არასავალდებულო: შექმენით მრავალჯერადი კომპონენტის მაკრო** (მაგ., ბარათი, alert-ი ან გვერდის სექცია) და გამოიყენეთ ის ერთ ან მეტ თქვენს გვერდზე.