# თავი 3: ინტერაქტიული ვებ აპლიკაციების შექმნა --- ## 3.1 ჩვენებიდან (Display) ინტერაქციამდე პირველ ორ თავში ჩვენ ავაშენეთ გვერდები, რომლებიც აჩვენებენ ინფორმაციას — სტატიკური კონტენტი, შაბლონის მიერ დარენდერებული განლაგებები (layouts) და controller-ებიდან model-ის მეშვეობით გადაცემული მონაცემები. მომხმარებელს შეეძლო კონტენტის ნახვა, მაგრამ არ შეეძლო უკან რაიმეს გაგზავნა. თუმცა, ნამდვილი ვებ აპლიკაცია არის საუბარი: მომხმარებელი აგზავნის (submits) მონაცემებს, სერვერი ამუშავებს მათ და აპლიკაცია შესაბამისად პასუხობს. ეს თავი წარმოგიდგენთ მექანიზმებს, რომლებიც ამ საუბარს შესაძლებელს ხდის. ჩვენ ვისწავლით, თუ როგორ დავამუშავოთ ფორმის გაგზავნა (form submissions), დავაკავშიროთ ფორმის მონაცემები Java ობიექტებთან, გადავამოწმოთ მომხმარებლის მიერ შეყვანილი მონაცემები სერვერის მხარეს, ვაჩვენოთ ვალიდაციის შეცდომები მომხმარებელს, დავამუშავოთ ფაილების ატვირთვა და ავიცილოთ თავიდან დუბლირებული გაგზავნის პრობლემა Post/Redirect/Get პატერნით. ჩვენ ასევე შევქმნით შეცდომის (error) მორგებულ გვერდებს. ამ თავში ფორმის ყველა რენდერინგი იყენებს **Spring-ის ჩაშენებულ FreeMarker მაკროებს** — `spring.ftl` ბიბლიოთეკას, რომელსაც პირველ თავში შევხვდით URL-ების გენერირებისთვის. ეს მაკროები უზრუნველყოფენ ფორმის დაკავშირებას (form binding), input-ების გენერაციას და შეცდომების ჩვენებას, რაც პირდაპირ ინტეგრირდება Spring MVC-ის data binding-ისა და ვალიდაციის ინფრასტრუქტურასთან. --- ## 3.2 HTTP GET და POST მოთხოვნების დამუშავება ვებ აპლიკაციასთან ნებისმიერი ინტერაქცია იწყება HTTP მოთხოვნით (request). ფორმაზე დაფუძნებულ ვებ აპლიკაციებში დომინირებს მოთხოვნის ორი მეთოდი: **GET** მოთხოვნები იღებენ (retrieve) მონაცემებს. როდესაც გადადიხართ URL-ზე, აკლიკებთ ბმულს ან კრეფთ მისამართს ბრაუზერის ველში, იგზავნება GET მოთხოვნა. GET მოთხოვნებმა არასოდეს უნდა შეცვალოს მონაცემები — ისინი უსაფრთხო და იდემპოტენტურია. **POST** მოთხოვნები აგზავნიან (submit) მონაცემებს. როდესაც ავსებთ ფორმას და აკლიკებთ "Submit"-ს, იგზავნება POST მოთხოვნა, რომლის ტანშიც (body) მოთავსებულია ფორმის მონაცემები. POST მოთხოვნები, როგორც წესი, ქმნიან ან ცვლიან რესურსს სერვერზე. Spring MVC-ში, handler მეთოდები `@Controller` კლასში უკავშირდება კონკრეტულ HTTP მეთოდებს `@GetMapping` და `@PostMapping` ანოტაციების გამოყენებით: ```java @Controller public class ProductController { private final ProductService productService; public ProductController(ProductService productService) { this.productService = productService; } @GetMapping("/products") public String listProducts(Model model) { model.addAttribute("products", productService.findAll()); return "products/list"; } @PostMapping("/products") public String createProduct(@ModelAttribute Product product) { productService.save(product); return "redirect:/products"; } } ``` ერთი და იგივე URL — `/products` — მუშავდება ორი განსხვავებული მეთოდის მიერ. Spring ანაწილებს მოთხოვნას სწორ მეთოდზე HTTP მეთოდის საფუძველზე. GET handler იღებს მონაცემებს და არენდერებს შაბლონს. POST handler ამუშავებს გამოგზავნილ ფორმის მონაცემებს და აკეთებს გადამისამართებას (redirect) (თუ რატომ აკეთებს გადამისამართებას პირდაპირ რენდერინგის ნაცვლად, განვიხილავთ 3.8 სექციაში). --- ## 3.3 ფორმების აშენება Spring-ის FreeMarker მაკროებით ისეთი HTML ფორმის ასაშენებლად, რომელიც ინტეგრირდება Spring MVC-ის data binding-თან, ჩვენ ვიყენებთ `spring.ftl`-ში განსაზღვრულ მაკროებს. ეს მაკროები აგენერირებენ ფორმის input ელემენტებს, რომლებიც ავტომატურად უკავშირდებიან (bound) მოდელში არსებულ ფორმის დამხმარე ობიექტს (form-backing object, რომელსაც ასევე უწოდებენ "command object"). ### ფორმის მომზადება Controller-ში სანამ ფორმა დარენდერდება, GET handler-მა მოდელში უნდა დაამატოს ცარიელი ობიექტი. ეს არის ის ობიექტი, რომელთანაც Spring დააკავშირებს ფორმის ველებს: ```java @GetMapping("/products/new") public String showCreateForm(Model model) { model.addAttribute("product", new Product()); return "products/create"; } ``` გასაღები `"product"` არის სახელი, რომლითაც ცნობილია ფორმის დამხმარე ობიექტი. შაბლონში, ფორმის მაკროს ყველა გზა (path) დაიწყება ამ სახელით. ### ფორმის შაბლონი (The Form Template) აი სრული ფორმა, რომელიც იყენებს Spring-ის FreeMarker მაკროებს: ```html <#import "/spring.ftl" as spring> <#import "layout.ftlh" as layout> <@layout.page title="Create Product">

Create a New Product

<@spring.formInput "product.name" 'id="name" class="form-control"'/> <@spring.showErrors "
" "error"/>
<@spring.formInput "product.price" 'id="price" class="form-control"' "number"/> <@spring.showErrors "
" "error"/>
<@spring.formTextarea "product.description" 'id="description" rows="5" class="form-control"'/> <@spring.showErrors "
" "error"/>
``` მოდით დავშალოთ, თუ რა ხდება აქ. `<@spring.formInput "product.name" 'id="name" class="form-control"'/>` აგენერირებს `` ელემენტს. პირველი არგუმენტი — `"product.name"` — არის **გზა (path)**: ფორმის დამხმარე ობიექტის სახელი (`product`), რომელსაც მოსდევს ველის სახელი (`name`). მაკრო უკავშირდება ამ გზას, რაც იმას ნიშნავს, რომ ის შეავსებს input-ის `value` ატრიბუტს ობიექტის `name` property-დან, და დაარქმევს სახელს input-ს ისე, რომ გამოგზავნილი მონაცემები უკან დაუკავშირდეს ამ property-ს. მეორე არგუმენტი არის დამატებითი HTML ატრიბუტების სტრიქონი, რომლებიც უნდა ჩაირთოს გენერირებულ ტეგში. `<@spring.formInput "product.price" '...' "number"/>` აჩვენებს არასავალდებულო მესამე არგუმენტს — ველის ტიპს. `"number"`-ის გადაცემით, მაკრო ნაგულისხმევი text input-ის ნაცვლად აგენერირებს ``-ს. აქ ასევე შეგიძლიათ გადასცეთ `"hidden"` ან `"password"`. `<@spring.formTextarea "product.description" '...'/>` აგენერირებს `