Spring in Action Covers Spring 5-1--11 — страница 9 из 63

@PostMapping public String processDesign(Design design) {


   // Save the taco design…


   // We'll do this in chapter 3


   log.info("Processing design: " + design);


   return "redirect:/orders/current";


}

Применительно к методу processDesign(),  @PostMapping взаимодействует с уровнем класса @RequestMapping, чтобы указать, что processDesign() должен обрабатывать POST-запросы для /design. Это именно то, что вам нужно для обработки представленных творений создателя тако.

При отправке формы поля в форме привязываются к свойствам объекта Taco (класс которого показан в следующем листинге), который передается в качестве параметра в processDesign(). Метод processDesign() может делать с объектом Taco все, что угодно.

Листинг 2.5 Объект домена, определяющий состав тако

package tacos;

import java.util.List;


import lombok.Data;



@Data public class Taco {


   private String name;


   private List ingredients;


}

Как вы можете видеть, Taco - это простой объект Java с несколькими свойствами. Как и ингредиент, класс Taco аннотируется @Data для автоматического создания необходимых методов JavaBean для вас во время выполнения.

Если вы посмотрите на форму в листинге 2.3, вы увидите несколько элементов checkbox, все с именем ingredients, и элемент ввода текста с именем name. Эти поля в форме соответствуют непосредственно ingredients и свойствам name класса Taco.

Поле Name в форме должно содержать только простое текстовое значение. Таким образом, свойство name Taco имеет тип String. У флажков "ингредиенты" также есть текстовые значения, но поскольку можно выбрать ни одного или несколько из них, свойство ingredients, к которому они привязаны, является List, которое будет включать каждый из выбранных ингредиентов.

На данный момент метод processDesign() ничего не делает с объектом Taco. На самом деле, он вообще ничего не делает. Все нормально. В главе 3 вы добавите некоторую логику сохраняемости, которая сохранит отправленное Taco в базу данных.

Как и в случае с методом showDesignForm(),  processDesign() завершается возвращением String значения. И так же, как showDesignForm(), возвращаемое значение указывает на представление, которое будет показано пользователю. Но отличается то, что значение, возвращаемое из processDesign(), имеет префикс "redirect:", указывающий, что это представление перенаправления. Более конкретно, это указывает, что после того, как processDesign() завершится, браузер пользователя должен быть перенаправлен к относительному пути /order/current.

Идея заключается в том, что после создания тако, пользователь будет перенаправлен на форму заказа, из которых он может разместить заказ, чтобы его творение - тако был доставлен. Но у вас еще нет контроллера, который будет обрабатывать запрос /orders/current.

Учитывая то, что вы теперь знаете о @Controller, @RequestMapping и @GetMapping, вы можете легко создать такой контроллер. Это может выглядеть примерно так:

Листинг 2.6 Контроллер для представления формы заказа тако

package tacos.web;

import javax.validation.Valid;


import org.springframework.stereotype.Controller;


import org.springframework.ui.Model;


import org.springframework.validation.Errors;


import org.springframework.web.bind.annotation.GetMapping;


import org.springframework.web.bind.annotation.RequestMapping;


import lombok.extern.slf4j.Slf4j;


import tacos.Order;



@Slf4j @Controller


@RequestMapping("/orders")


public class OrderController {


   @GetMapping("/current")


   public String orderForm(Model model) {


      model.addAttribute("order", new Order());


      return "orderForm";


   }


}

Вы используете @Slf4j аннотацию Lombok для создания свободного объекта slf4j Logger во время выполнения. Вы будете использовать этот регистратор в момент получения деталей заказа, который был создан.

@RequestMapping уровня класса указывает, что любые методы обработки запросов в этом контроллере будут обрабатывать запросы, путь к которым начинается с /orders. В сочетании с методом уровня @GetMapping, он указывает, что метод orderForm() будет обрабатывать HTTP GET запросы для /orders/current.

Что касается самого метода orderForm(), он чрезвычайно прост, возвращая только логическое имя представления orderForm. Как только у вас будет способ сохранить созданного тако в базе данных в главе 3, вы вернетесь к этому методу и измените его, чтобы заполнить модель списком объектов Taco, которые будут размещены в очереди.

Представление формы заказа предоставляется шаблоном Thymeleaf с именем orderForm.html, который показан далее.

Листинг 2.7 Вид формы заказа тако



xmlns:th="http://www.thymeleaf.org">



Taco Cloud






Order your taco creations!



Design another taco




           Please correct the problems below and resubmit.




Deliver my taco masterpieces to...






















Here's how I'll pay...

















По большей части, orderForm.html отображение - это типичный HTML/Thymeleaf контент, с очень небольшим количеством заметок. Но обратите внимание, что тег

здесь отличается от тега , используемого в листинге 2.3, тем, что он также определяет действие формы. Без указанного действия форма отправит запрос HTTP POST обратно на тот же URL-адрес, что и форма. Но здесь вы указываете, что форма должна заPOSTедь в /orders (используя оператор Thymeleaf @{...} для относительного контекста).

Поэтому в класс OrderController необходимо добавить еще один метод, обрабатывающий POST-запросы для /orders. У вас не будет способа сохранять заказы до следующей главы, поэтому поставим заглушку здесь-что-то вроде той, что вы видите в следующем листинге:

Листинг 2.8 обработка отправки заказа тако

@PostMapping


public String processOrder(Order order) {


   log.info("Order submitted: " + order);


   return "redirect:/";


}

При вызове метода processOrder() для обработки отправленного заказа ему присваивается объект Order, свойства которого привязаны к полям отправленной формы. Order, как и Taco, является довольно простым классом,который несет информацию о заказе.

Листинг 2.9 доменный объект для заказов тако

package tacos;

import javax.validation.constraints.Digits;


import javax.validation.constraints.Pattern;


import org.hibernate.validator.constraints.CreditCardNumber;


import org.hibernate.validator.constraints.NotBlank;


import lombok.Data;



@Data


public class Order {


   private String name;


   private String street;


   private String city;


   private String state;


   private String zip;


   private String ccNumber;


   private String ccExpiration;


   private String ccCVV;


}

Теперь, когда вы разработали OrderController и представление формы заказа, вы готовы испытать его. Откройте браузер, с адресом http://localhost:8080/design, выберите некоторые ингредиенты для вашего тако,и нажмите кнопку Submit Your Taco. Вы должны увидеть форму, подобную показанной на рис. 2.3.

Заполните некоторые поля формы и нажмите кнопку Submit Order. И следите за логами приложений, чтобы увидеть информацию о вашем заказе. Когда я нажал, запись лога выглядела примерно так (переформатирована, чтобы соответствовать ширине этой страницы):

Order submitted: Order(name=Craig Walls,street1=1234 7th Street, city=Somewhere, state=Who knows?, zip=zipzap, ccNumber=Who can guess?, ccExpiration=Some day, ccCVV=See-vee-vee)

Если вы внимательно посмотрите на запись лога из моего тестового заказа, вы увидите, что хотя метод processOrder() выполнил свою работу и обработал отправку формы, он позволил пройти немного не корректной информации. Большинство полей в форме содержат данные, которые не могут быть правильными. Давайте добавим некоторую проверку, чтобы убедиться, что предоставленные данные по крайней мере похожи на требуемую информацию.


Рисунок 2.3

2.3 Проверка формы ввода

При сборке созданного тако, что делать, если пользователь не выбирает ингредиенты или не указал имя при создании? При отправке заказа, что делать, если создатель тако не заполнил необходимые поля адреса? Или что, если он ввел значение в поле кредитной карты, которое не является действительным номером кредитной карты?