1. Обзор
Для конечного пользователя процесс отправки формы удобен и в некоторой степени эквивалентен простому вводу данных и нажатию кнопки отправки. Однако с инженерной точки зрения для надежной отправки и получения этих данных с клиентской стороны на серверную для внутренней обработки требуется механизм кодирования.
В рамках этого руководства мы сосредоточимся на создании формы, которая отправляет свои данные как тип контента application/x-www-form-urlencoded
в веб-приложении Spring.
2. Кодирование данных формы
Наиболее часто используемый метод HTTP для отправки форм — POST. Однако для идемпотентной отправки формы мы также можем использовать метод HTTP GET. И способ указать метод — через атрибут метода формы .
Для форм, использующих метод GET, все данные формы отправляются как часть строки запроса. Но если мы используем метод POST, то его данные отправляются как часть тела HTTP-запроса.
Более того, в последнем случае мы также можем указать кодировку данных с помощью атрибута enctype
формы , который может принимать два значения, а именно application/x-www-form-urlencoded
и multipart/form-data
.
2.1. Тип носителя application/x-www-form-urlencoded
HTML - формы имеют значение по умолчанию application/x-www-form-urlencoded
для атрибута enctype
, так как это касается основных случаев использования, когда данные полностью текстовые. Тем не менее, если наш вариант использования включает поддержку файловых данных, нам придется переопределить его значением multipart/form-data
.
По сути, он отправляет данные формы в виде пар ключ-значение, разделенных символом амперсанда (&). Кроме того, соответствующие ключ и значение разделяются знаком равенства (=). Кроме того, все зарезервированные и не буквенно-цифровые символы кодируются с использованием процентного кодирования .
3. Отправка формы в браузере
Теперь, когда мы рассмотрели наши основы, давайте продолжим и посмотрим, как мы можем обрабатывать данные формы, закодированные в URL-адресе, для простого варианта использования отправки обратной связи в веб-приложении Spring.
3.1. Модель домена
Для нашей формы обратной связи нам нужно захватить идентификатор электронной почты отправителя вместе с комментарием. Итак, давайте создадим нашу модель предметной области в классе Feedback
:
public class Feedback {
private String emailId;
private String comment;
}
3.2. Создать форму
Чтобы использовать простой шаблон HTML для создания нашей динамической веб-формы, нам нужно настроить Thymeleaf в нашем проекте. После этого мы готовы добавить конечную точку GET /feedback
, которая будет обслуживать представление обратной
связи для формы :
@GetMapping(path = "/feedback")
public String getFeedbackForm(Model model) {
Feedback feedback = new Feedback();
model.addAttribute("feedback", feedback);
return "feedback";
}
Обратите внимание, что мы используем обратную связь
в качестве атрибута модели для захвата пользовательского ввода. Далее создадим представление обратной
связи в шаблоне feedback.html
:
<form action="#" method="post" th:action="@{/web/feedback}" th:object="${feedback}">
<!-- form fields for feedback's submitter and comment info -->
</form>
Конечно, нам не нужно явно указывать атрибут enctype
, так как он выберет значение по умолчанию application/x-www-form-urlencoded
.
3.3. Поток PRG
Поскольку мы принимаем пользовательский ввод через форму обратной связи браузера, мы должны реализовать рабочий процесс отправки POST/REDIRECT/GET (PRG), чтобы избежать дублирования отправки .
Во-первых, давайте реализуем конечную точку POST /web/feedback
, которая будет действовать как обработчик действий для формы обратной связи:
@PostMapping(
path = "/web/feedback",
consumes = {MediaType.APPLICATION_FORM_URLENCODED_VALUE})
public String handleBrowserSubmissions(Feedback feedback) throws Exception {
// Save feedback data
return "redirect:/feedback/success";
}
Затем мы можем реализовать конечную точку перенаправления /feedback/success
, которая обслуживает запрос GET:
@GetMapping("/feedback/success")
public ResponseEntity<String> getSuccess() {
return new ResponseEntity<String>("Thank you for submitting feedback.", HttpStatus.OK);
}
Чтобы проверить функциональность рабочего процесса отправки формы в браузере, давайте посетим localhost:8080/feedback
:
Наконец, мы также можем проверить, что данные формы отправляются в форме, закодированной в URL:
emailId=abc%40example.com&comment=Sample+Feedback
4. Небраузерные запросы
Иногда у нас может не быть HTTP-клиента на основе браузера. Вместо этого нашим клиентом может быть такая утилита, как cURL или Postman . В таком случае нам не нужна веб-форма HTML. Вместо этого мы можем реализовать конечную точку /feedback
, которая обслуживает запрос POST:
@PostMapping(
path = "/feedback",
consumes = {MediaType.APPLICATION_FORM_URLENCODED_VALUE})
public ResponseEntity<String> handleNonBrowserSubmissions(@RequestBody Feedback feedback) throws Exception {
// Save feedback data
return new ResponseEntity<String>("Thank you for submitting feedback", HttpStatus.OK);
}
При отсутствии HTML-формы в нашем потоке данных нам не обязательно реализовывать шаблон PRG. Однако мы должны указать, что ресурс принимает медиа-тип APPLICATION_FORM_URLENCODED_VALUE
.
Наконец, мы можем проверить это с помощью запроса cURL:
curl -X POST \
http://localhost:8080/feedback \
-H 'Content-Type: application/x-www-form-urlencoded' \
-d 'emailId=abc%40example.com&comment=Sample%20Feedback'
4.1. Основы FormHttpMessageConverter
HTTP-запрос, который отправляет данные application/x-www-form-urlencoded
, должен указывать это в заголовке Content-Type .
Внутри Spring использует класс FormHttpMessageConverter
для чтения этих данных и связывания их с параметром метода.
В тех случаях, когда параметр нашего метода имеет тип MultiValueMap
, мы можем использовать аннотацию @RequestParam
или @RequestBody
, чтобы соответствующим образом связать его с телом HTTP-запроса. Это связано с тем, что Servlet API объединяет параметры запроса и данные формы в единую карту, называемую параметрами
, и включает автоматический анализ тела запроса:
@PostMapping(
path = "/feedback",
consumes = {MediaType.APPLICATION_FORM_URLENCODED_VALUE})
public ResponseEntity<String> handleNonBrowserSubmissions(
@RequestParam MultiValueMap<String,String> paramMap) throws Exception {
// Save feedback data
return new ResponseEntity<String>("Thank you for submitting feedback", HttpStatus.OK);
}
Однако для параметра метода типа, отличного от MultiValueMap,
такого как наш объект домена Feedback , мы должны использовать только аннотацию
@RequestBody
.
5. Вывод
В этом руководстве мы кратко узнали о кодировании данных формы в веб-формах. Мы также изучили, как обрабатывать закодированные URL-данные для браузерных и небраузерных HTTP-запросов, реализовав форму обратной связи в веб-приложении Spring Boot.
Как всегда, полный исходный код руководства доступен на GitHub .