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

Почтовый запрос RestTemplate с JSON

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

1. Введение

В этом кратком руководстве мы покажем, как использовать Spring RestTemplate для выполнения запросов POST, отправляющих содержимое JSON.

2. Настройка примера

Начнем с добавления простого класса модели Person для представления публикуемых данных:

public class Person {
private Integer id;
private String name;

// standard constructor, getters, setters
}

Для работы с объектами Person мы добавим интерфейс PersonService и реализацию с двумя методами:

public interface PersonService {

public Person saveUpdatePerson(Person person);
public Person findPersonById(Integer id);
}

Реализация этих методов просто вернет объект. Здесь мы используем фиктивную реализацию этого слоя, чтобы мы могли сосредоточиться на веб-слое.

3. Настройка REST API

Давайте определим простой REST API для нашего класса Person :

@PostMapping(
value = "/createPerson", consumes = "application/json", produces = "application/json")
public Person createPerson(@RequestBody Person person) {
return personService.saveUpdatePerson(person);
}

@PostMapping(
value = "/updatePerson", consumes = "application/json", produces = "application/json")
public Person updatePerson(@RequestBody Person person, HttpServletResponse response) {
response.setHeader("Location", ServletUriComponentsBuilder.fromCurrentContextPath()
.path("/findPerson/" + person.getId()).toUriString());

return personService.saveUpdatePerson(person);
}

Помните, мы хотим публиковать данные в формате JSON. Для этого мы добавили атрибут потребления в аннотацию @PostMapping со значением «application/json» `` для обоих методов.

Точно так же мы устанавливаем для атрибута «products» значение «application/json», чтобы сообщить Spring, что нам нужен текст ответа в формате JSON.

Мы аннотировали параметр person аннотацией @RequestBody для обоих методов. Это сообщит Spring, что объект person будет привязан к телу HTTP - запроса.

Наконец, оба метода возвращают объект Person , который будет привязан к телу ответа. Отметим, что мы аннотируем наш класс API с помощью @RestController , чтобы аннотировать все методы API скрытой аннотацией @ResponseBody .

4. Использование RestTemplate

Теперь мы можем написать несколько модульных тестов для проверки нашего Person REST API. Здесь мы попытаемся отправить POST-запросы к Person API, используя методы POST, предоставляемые RestTemplate : postForObject , postForEntity и postForLocation .

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

@BeforeClass
public static void runBeforeAllTestMethods() {
createPersonUrl = "http://localhost:8082/spring-rest/createPerson";
updatePersonUrl = "http://localhost:8082/spring-rest/updatePerson";

restTemplate = new RestTemplate();
headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
personJsonObject = new JSONObject();
personJsonObject.put("id", 1);
personJsonObject.put("name", "John");
}

Помимо этого метода настройки, обратите внимание, что мы будем обращаться к следующему преобразователю для преобразования строки JSON в объект JSONNode в наших модульных тестах:

private final ObjectMapper objectMapper = new ObjectMapper();

Как упоминалось ранее, мы хотим опубликовать данные в формате JSON. Для этого мы добавим заголовок Content-Type в наш запрос с типом мультимедиа APPLICATION_JSON .

Класс Spring HttpHeaders предоставляет различные методы для доступа к заголовкам. Здесь мы устанавливаем заголовок Content-Type в application/json , вызывая метод setContentType . Мы прикрепим объект заголовков к нашим запросам.

4.1. Отправка JSON с помощью postForObject

` Метод RestTemplate postForObject создает новый ресурс, отправляя объект в заданный шаблон URI. Он возвращает результат, автоматически преобразованный в тип, указанный в параметре responseType` .

Допустим, мы хотим сделать POST-запрос к нашему Person API, чтобы создать новый объект Person и вернуть этот вновь созданный объект в ответ.

Сначала мы создадим объект запроса типа HttpEntity на основе personJsonObject и заголовков, содержащих Content-Type . Это позволяет методу postForObject отправлять тело запроса JSON:

@Test
public void givenDataIsJson_whenDataIsPostedByPostForObject_thenResponseBodyIsNotNull()
throws IOException {
HttpEntity<String> request =
new HttpEntity<String>(personJsonObject.toString(), headers);

String personResultAsJsonStr =
restTemplate.postForObject(createPersonUrl, request, String.class);
JsonNode root = objectMapper.readTree(personResultAsJsonStr);

assertNotNull(personResultAsJsonStr);
assertNotNull(root);
assertNotNull(root.path("name").asText());
}

Метод postForObject() возвращает тело ответа в виде типа String .

Мы также можем вернуть ответ как объект Person , установив параметр responseType :

Person person = restTemplate.postForObject(createPersonUrl, request, Person.class);

assertNotNull(person);
assertNotNull(person.getName());

На самом деле наш метод обработчика запросов, соответствующий URI createPersonUrl, создает тело ответа в формате JSON.

Но для нас это не ограничение — postForObject умеет автоматически преобразовывать тело ответа в запрошенный тип Java (например , String , Person ), указанный в параметре responseType .

4.2. Отправка JSON с помощью postForEntity

По сравнению с postForObject() , postForEntity() возвращает ответ как объект ResponseEntity . В остальном оба метода выполняют одну и ту же работу.

Допустим, мы хотим сделать POST-запрос к нашему Person API, чтобы создать новый объект Person и вернуть ответ в виде ResponseEntity .

Мы можем использовать метод postForEntity для реализации этого:

@Test
public void givenDataIsJson_whenDataIsPostedByPostForEntity_thenResponseBodyIsNotNull()
throws IOException {
HttpEntity<String> request =
new HttpEntity<String>(personJsonObject.toString(), headers);

ResponseEntity<String> responseEntityStr = restTemplate.
postForEntity(createPersonUrl, request, String.class);
JsonNode root = objectMapper.readTree(responseEntityStr.getBody());

assertNotNull(responseEntityStr.getBody());
assertNotNull(root.path("name").asText());
}

Подобно postForObject , postForEntity имеет параметр responseType для преобразования тела ответа в запрошенный тип Java.

Здесь мы смогли вернуть тело ответа как ResponseEntity<String> .

Мы также можем вернуть ответ как объект ResponseEntity<Person> , установив для параметра responseType значение Person.class :

ResponseEntity<Person> responseEntityPerson = restTemplate.
postForEntity(createPersonUrl, request, Person.class);

assertNotNull(responseEntityPerson.getBody());
assertNotNull(responseEntityPerson.getBody().getName());

4.3. Отправка JSON с postForLocation

Подобно методам postForObject и postForEntity , postForLocation также создает новый ресурс, отправляя данный объект на заданный URI. Единственное отличие состоит в том, что он возвращает значение заголовка Location .

Помните, мы уже видели, как установить заголовок Location ответа в нашем методе updatePerson REST API выше:

response.setHeader("Location", ServletUriComponentsBuilder.fromCurrentContextPath()
.path("/findPerson/" + person.getId()).toUriString());

Теперь давайте представим, что мы хотим вернуть заголовок Location ответа после обновления опубликованного объекта человека .

Мы можем реализовать это с помощью метода postForLocation :

@Test
public void givenDataIsJson_whenDataIsPostedByPostForLocation_thenResponseBodyIsTheLocationHeader()
throws JsonProcessingException {
HttpEntity<String> request = new HttpEntity<String>(personJsonObject.toString(), headers);
URI locationHeader = restTemplate.postForLocation(updatePersonUrl, request);

assertNotNull(locationHeader);
}

5. Вывод

В этой статье мы рассмотрели, как использовать RestTemplate для отправки запроса POST с помощью JSON.

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