«1. Обзор

В этом коротком руководстве мы подробно рассмотрим, как работать с параметрами JSON в Spring MVC.

Во-первых, мы начнем с небольшой предыстории параметров JSON. Затем мы спустимся в кроличью нору, чтобы увидеть, как отправлять параметры JSON в запросах POST и GET.

2. Параметры JSON в Spring MVC

Использование JSON для отправки или получения данных является обычной практикой среди веб-разработчиков. Иерархическая структура строк JSON предлагает более компактный и удобочитаемый способ представления параметров HTTP-запроса.

По умолчанию Spring MVC обеспечивает готовую привязку данных для простых типов данных, таких как String. Для этой цели он использует список встроенных редакторов свойств под капотом.

Однако в реальных проектах мы можем захотеть связать более сложные типы данных. Например, может быть удобно иметь возможность сопоставить параметр JSON с объектом модели.

3. Отправка данных JSON в POST

Spring предоставляет простой способ отправки данных JSON через запросы POST. Встроенная аннотация @RequestBody может автоматически десериализовать данные JSON, инкапсулированные в теле запроса, в конкретный объект модели.

Как правило, нам не нужно самостоятельно разбирать тело запроса. Мы можем использовать библиотеку Джексона, чтобы сделать всю тяжелую работу за нас.

Теперь давайте посмотрим, как отправлять данные JSON через запрос POST в Spring MVC.

Во-первых, нам нужно создать объект модели для представления переданных данных JSON. Например, рассмотрим класс Product:

public class Product {

    private int id;
    private String name;
    private double price;

    // default constructor + getters + setters

}

Во-вторых, давайте определим метод обработчика Spring, который принимает запросы POST:

@PostMapping("/create")
@ResponseBody
public Product createProduct(@RequestBody Product product) {
    // custom logic
    return product;
}

Как мы видим, аннотировать аргумент продукта с помощью @RequestBody достаточно для привязки Данные JSON, отправленные от клиентов.

Теперь мы можем протестировать наш запрос POST, используя cURL:

curl -i \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-X POST --data \
  '{"id": 1,"name": "Asus Zenbook","price": 800}' "http://localhost:8080/spring-mvc-basics-4/products/create"

4. Отправьте параметр JSON в GET

Spring MVC предлагает @RequestParam для извлечения параметров запроса из запросов GET. Однако, в отличие от @RequestBody, аннотация @RequestParam поддерживает только простые типы данных, такие как int и String.

Итак, чтобы отправить JSON, нам нужно определить наш параметр JSON как простую строку.

Большой вопрос здесь: как нам преобразовать наш параметр JSON (который является строкой) в объект класса Product?

Ответ довольно прост! Класс ObjectMapper, предоставляемый библиотекой Jackson, предлагает гибкий способ преобразования строк JSON в объекты Java.

Теперь давайте посмотрим, как отправить параметр JSON через запрос GET в Spring MVC. Во-первых, нам нужно создать еще один метод-обработчик в нашем контроллере для обработки запросов GET:

@GetMapping("/get")
@ResponseBody
public Product getProduct(@RequestParam String product) throws JsonMappingException, JsonProcessingException {
    Product prod = objectMapper.readValue(product, Product.class);
    return prod;
}

Как показано выше, метод readValue() позволяет десериализовать продукт параметра JSON непосредственно в экземпляр класса Product.

Обратите внимание, что мы определяем наш параметр запроса JSON как объект String. А что, если мы хотим передать объект Product, как при использовании @RequestBody?

Чтобы ответить на этот вопрос, Spring предлагает краткое и гибкое решение с помощью пользовательских редакторов свойств.

Во-первых, нам нужно создать редактор настраиваемых свойств, чтобы инкапсулировать логику преобразования параметра JSON, заданного как String, в объект Product:

public class ProductEditor extends PropertyEditorSupport {

    private ObjectMapper objectMapper;

    public ProductEditor(ObjectMapper objectMapper) {
        this.objectMapper = objectMapper;
    }

    @Override
    public void setAsText(String text) throws IllegalArgumentException {
        if (StringUtils.isEmpty(text)) {
            setValue(null);
        } else {
            Product prod = new Product();
            try {
                prod = objectMapper.readValue(text, Product.class);
            } catch (JsonProcessingException e) {
                throw new IllegalArgumentException(e);
            }
            setValue(prod);
        }
    }

}

Затем давайте привяжем параметр JSON к объекту Класс продукта:

@GetMapping("/get2")
@ResponseBody
public Product get2Product(@RequestParam Product product) {
    // custom logic
    return product;
}

Наконец, нам нужно добавить последний недостающий элемент головоломки. Давайте зарегистрируем ProductEditor в нашем контроллере Spring:

@InitBinder
public void initBinder(WebDataBinder binder) {
    binder.registerCustomEditor(Product.class, new ProductEditor(objectMapper));
}

Имейте в виду, что нам нужно URL-кодировать параметр JSON для обеспечения безопасной транспортировки.

Итак, вместо:

GET /spring-mvc-basics-4/products/get2?product={"id": 1,"name": "Asus Zenbook","price": 800}

Нам нужно отправить:

GET /spring-mvc-basics-4/products/get2?product=%7B%22id%22%3A%201%2C%22name%22%3A%20%22Asus%20Zenbook%22%2C%22price%22%3A%20800%7D

5. Заключение

Подводя итог, мы увидели, как работать с JSON в Spring MVC. Попутно мы продемонстрировали, как отправлять параметры JSON в запросах POST и GET.

Как всегда, полный исходный код примеров доступен на GitHub.