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 .