Перейти к основному содержимому

Обработка данных формы, закодированных в URL-адресе, в Spring REST

· 5 мин. чтения

Задача: Сумма двух чисел

Напишите функцию twoSum. Которая получает массив целых чисел nums и целую сумму target, а возвращает индексы двух чисел, сумма которых равна target. Любой набор входных данных имеет ровно одно решение, и вы не можете использовать один и тот же элемент дважды. Ответ можно возвращать в любом порядке...

ANDROMEDA

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 :

./e707c4855f6b0a0bbb0e4a94df338418.png

Наконец, мы также можем проверить, что данные формы отправляются в форме, закодированной в 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 .