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

Как установить тип содержимого JSON в Spring MVC

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

1. Введение

Тип содержимого указывает, как интерпретировать данные, присутствующие в запросе/ответе. Всякий раз, когда контроллер получает веб-запрос, он потребляет или создает некоторые типы мультимедиа. В этой модели «запрос-ответ» можно потреблять/производить несколько типов мультимедиа, и JSON является одним из них.

В этом кратком руководстве мы рассмотрим различные способы установки типа контента в Spring MVC.

2. @RequestMapping весной

Проще говоря, @RequestMapping — это важная аннотация, которая сопоставляет веб-запросы с контроллером Spring. Он имеет различные атрибуты, включая метод HTTP, параметры запроса, заголовки и типы мультимедиа.

Как правило, типы носителей делятся на две категории: расходуемые и производимые. Помимо этих двух, мы также можем определить собственный тип носителя в Spring . Основная цель состоит в том, чтобы ограничить первичное сопоставление списком типов мультимедиа для нашего обработчика запросов.

2.1. Тип расходного материала

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

@RequestMapping(value = "/greetings", method = RequestMethod.POST, consumes="application/json")
public void addGreeting(@RequestBody ContentType type, Model model) {
// code here
}

Если клиент указывает тип носителя, который не может быть использован ресурсом, система выдаст ошибку HTTP «415 Unsupported Media Type».

2.2. Тип производимого носителя

В отличие от атрибута « использует», атрибут « products » определяет тип мультимедиа, который ресурс может создавать и отправлять обратно клиенту. Без сомнения, мы можем использовать список вариантов. Если ресурс не может создать запрошенный ресурс, система выдаст ошибку HTTP «406 Not Acceptable».

Давайте начнем с простого примера — API, предоставляющий строку JSON.

Вот наша конечная точка:

@RequestMapping(
value = "/greetings-with-response-body",
method = RequestMethod.GET,
produces="application/json"
)
@ResponseBody
public String getGreetingWhileReturnTypeIsString() {
return "{\"test\": \"Hello using @ResponseBody\"}";
}

Давайте проверим это с помощью CURL:

curl http://localhost:8080/greetings-with-response-body

Приведенная выше команда выдает ответ:

{ "test": "Hello using @ResponseBody" }

В зависимости от типа содержимого, представленного в заголовке, @ResponseBody только привязывает возвращаемое значение метода к телу веб-ответа.

3. Content-Type установлен неправильно

Когда метод имеет тип возвращаемого значения String, а JSON Mapper отсутствует в пути к классам. В этом случае возвращаемое значение обрабатывается классом StringHttpMessageConverter , который устанавливает тип содержимого «текстовый/обычный». Это часто приводит к проблеме, когда контроллер не может создать ожидаемый тип контента.

Рассмотрим разные подходы к решению этой проблемы.

3.1. Использование @ ResponseBody с JSON Mapper

Класс Jackson ObjectMapper анализирует JSON из строки, потока или файла. Если Джексон находится в пути к классам, любой контроллер в приложениях Spring по умолчанию отображает ответ JSON.

Чтобы включить Джексона в путь к классам, нам нужно добавить следующую зависимость в pom.xml :

<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.12.4</version>
</dependency>

Давайте добавим модульный тест для проверки из ответа:

@Test
public void givenReturnTypeIsString_whenJacksonOnClasspath_thenDefaultContentTypeIsJSON()
throws Exception {

// Given
String expectedMimeType = "application/json";

// Then
String actualMimeType = this.mockMvc.perform(MockMvcRequestBuilders.get("/greetings-with-response-body", 1))
.andReturn().getResponse().getContentType();

Assert.assertEquals(expectedMimeType, actualMimeType);
}

3.2. Использование ResponseEntiy

В отличие от @ResponseBody , ResponseEntity является универсальным типом, представляющим весь HTTP-ответ. В результате мы можем контролировать все, что в него входит: код состояния, заголовок и тело.

Давайте определим новую конечную точку:

@RequestMapping(
value = "/greetings-with-response-entity",
method = RequestMethod.GET,
produces = "application/json"
)
public ResponseEntity<String> getGreetingWithResponseEntity() {
final HttpHeaders httpHeaders= new HttpHeaders();
httpHeaders.setContentType(MediaType.APPLICATION_JSON);
return new ResponseEntity<String>("{\"test\": \"Hello with ResponseEntity\"}", httpHeaders, HttpStatus.OK);
}

В консоли разработчика нашего браузера мы видим следующий ответ:

{"test": "Hello with ResponseEntity"}

С ResponseEntity у нас должен быть управляемый аннотациями тег в нашем диспетчерском сервлете :

<mvc:annotation-driven />

Проще говоря, приведенный выше тег дает больший контроль над внутренней работой Spring MVC .

Давайте проверим тип содержимого ответа с помощью тестового примера:

@Test
public void givenReturnTypeIsResponseEntity_thenDefaultContentTypeIsJSON() throws Exception {

// Given
String expectedMimeType = "application/json";

// Then
String actualMimeType = this.mockMvc.perform(MockMvcRequestBuilders.get("/greetings-with-response-entity", 1))
.andReturn().getResponse().getContentType();

Assert.assertEquals(expectedMimeType, actualMimeType);
}

3.3. Использование возвращаемого типа Map<String, Object>

И последнее, но не менее важное: мы также можем установить тип содержимого, изменив тип возвращаемого значения со String на Map . Этот тип возвращаемого значения Map потребует маршалинга и возвращает объект JSON.

Вот наша новая конечная точка:

@RequestMapping(
value = "/greetings-with-map-return-type",
method = RequestMethod.GET,
produces = "application/json"
)
@ResponseBody
public Map<String, Object> getGreetingWhileReturnTypeIsMap() {
HashMap<String, Object> map = new HashMap<String, Object>();
map.put("test", "Hello from map");
return map;
}

Давайте посмотрим на это в действии:

curl http://localhost:8080/greetings-with-map-return-type

Команда curl возвращает ответ JSON:

{ "test": "Hello from map" }

4. Вывод

В этой статье объясняется, как установить тип содержимого в Spring MVC, сначала добавив сопоставитель Json в путь к классам, затем используя ResponseEntity и, наконец, изменив тип возвращаемого значения со String на Map.

Как всегда, все фрагменты кода можно найти на GitHub .