Articles

Przewodnik po RestTemplate

Posted on

Overview

W tym tutorialu zamierzamy zilustrować szeroki zakres operacji, w których klient Spring REST – RestTemplate – może być używany, i to używany dobrze.

Dla strony API wszystkich przykładów, będziemy uruchamiać usługę RESTful z tego miejsca.

Dalsza lektura:

Podstawowe uwierzytelnianie za pomocą RestTemplate

Jak wykonać podstawowe uwierzytelnianie za pomocą Spring RestTemplate.
Czytaj więcej →

RestTemplate with Digest Authentication

Jak skonfigurować Digest Authentication dla Spring RestTemplate przy użyciu HttpClient 4.
Czytaj więcej →

Poznanie Spring Boot TestRestTemplate

Naucz się, jak używać nowego TestRestTemplate w Spring Boot do testowania prostego API.
Czytaj więcej →

Deprecation Notice

Począwszy od Spring Framework 5, wraz ze stosem WebFlux, Spring wprowadził nowego klienta HTTP o nazwie WebClient.

WebClient jest nowoczesnym, alternatywnym klientem HTTP do RestTemplate. Nie tylko dostarcza on tradycyjne synchroniczne API, ale także wspiera wydajne nieblokujące i asynchroniczne podejście.

Jeśli tworzymy nowe aplikacje lub migrujemy stare, dobrym pomysłem jest użycie WebClienta. Idąc dalej, RestTemplate zostanie zdeprecjonowany w przyszłych wersjach.

Użyj GET aby pobrać zasoby

3.1. Get Plain JSON

Zacznijmy od prostego omówienia żądań GET, z szybkim przykładem wykorzystującym API getForEntity():

RestTemplate restTemplate = new RestTemplate();String fooResourceUrl = "http://localhost:8080/spring-rest/foos";ResponseEntity<String> response = restTemplate.getForEntity(fooResourceUrl + "/1", String.class);assertThat(response.getStatusCode(), equalTo(HttpStatus.OK));

Zauważ, że mamy pełny dostęp do odpowiedzi HTTP, więc możemy robić takie rzeczy jak sprawdzenie kodu statusu, aby upewnić się, że operacja się powiodła lub pracować z faktyczną treścią odpowiedzi:

ObjectMapper mapper = new ObjectMapper();JsonNode root = mapper.readTree(response.getBody());JsonNode name = root.path("name");assertThat(name.asText(), notNullValue());

Pracujemy tutaj z ciałem odpowiedzi jako standardowym Stringiem i używamy Jacksona (oraz struktury węzłów JSON, którą Jackson dostarcza) do weryfikacji niektórych szczegółów.

3.2. Pobieranie POJO zamiast JSON

Możemy również zmapować odpowiedź bezpośrednio do Resource DTO:

public class Foo implements Serializable { private long id; private String name; // standard getters and setters}

Teraz możemy po prostu użyć API getForObject w szablonie:

Foo foo = restTemplate .getForObject(fooResourceUrl + "/1", Foo.class);assertThat(foo.getName(), notNullValue());assertThat(foo.getId(), is(1L));

Użyj HEAD do pobierania nagłówków

Przyjrzyjrzyjmy się teraz szybko użyciu HEAD zanim przejdziemy do bardziej powszechnych metod.

Będziemy tutaj używać API headForHeaders():

HttpHeaders httpHeaders = restTemplate.headForHeaders(fooResourceUrl);assertTrue(httpHeaders.getContentType().includes(MediaType.APPLICATION_JSON));

Użyj POST aby utworzyć Zasób

Aby utworzyć nowy Zasób w API, możemy zrobić dobry użytek z API postForLocation(), postForObject() lub postForEntity().

Pierwsze z nich zwraca URI nowo utworzonego Zasobu, podczas gdy drugie zwraca sam Zasób.

5.1. The postForObject() API

RestTemplate restTemplate = new RestTemplate();HttpEntity<Foo> request = new HttpEntity<>(new Foo("bar"));Foo foo = restTemplate.postForObject(fooResourceUrl, request, Foo.class);assertThat(foo, notNullValue());assertThat(foo.getName(), is("bar"));

5.2. API postForLocation()

Podobnie, przyjrzyjmy się operacji, która zamiast zwracać pełny Zasób, zwraca tylko Lokalizację tego nowo utworzonego Zasobu:

HttpEntity<Foo> request = new HttpEntity<>(new Foo("bar"));URI location = restTemplate .postForLocation(fooResourceUrl, request);assertThat(location, notNullValue());

5.3. The exchange() API

Spójrzmy jak zrobić POST z bardziej ogólnym API wymiany:

RestTemplate restTemplate = new RestTemplate();HttpEntity<Foo> request = new HttpEntity<>(new Foo("bar"));ResponseEntity<Foo> response = restTemplate .exchange(fooResourceUrl, HttpMethod.POST, request, Foo.class); assertThat(response.getStatusCode(), is(HttpStatus.CREATED)); Foo foo = response.getBody(); assertThat(foo, notNullValue());assertThat(foo.getName(), is("bar"));

5.4. Przesyłanie danych z formularza

Następnie przyjrzyjmy się, jak przesłać formularz metodą POST.

Po pierwsze, musimy ustawić nagłówek Content-Type na application/x-www-form-urlencoded.

Dzięki temu do serwera może zostać wysłany duży ciąg zapytania, zawierający pary nazwa/wartość oddzielone &:

HttpHeaders headers = new HttpHeaders();headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);

Możemy zawinąć zmienne formularza w LinkedMultiValueMap:

MultiValueMap<String, String> map= new LinkedMultiValueMap<>();map.add("id", "1");

Następnie budujemy Request używając instancji HttpEntity:

HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<>(map, headers);

Na koniec możemy połączyć się z usługą REST wywołując restTemplate.postForEntity() na punkcie końcowym: /foos/form

ResponseEntity<String> response = restTemplate.postForEntity( fooResourceUrl+"/form", request , String.class); assertThat(response.getStatusCode(), is(HttpStatus.CREATED));

Use OPTIONS to Get Allowed Operations

Następnie przyjrzymy się szybko użyciu żądania OPTIONS i zbadaniu dozwolonych operacji na konkretnym URI przy użyciu tego rodzaju żądania; API to optionsForAllow:

Set<HttpMethod> optionsForAllow = restTemplate.optionsForAllow(fooResourceUrl);HttpMethod supportedMethods = {HttpMethod.GET, HttpMethod.POST, HttpMethod.PUT, HttpMethod.DELETE};assertTrue(optionsForAllow.containsAll(Arrays.asList(supportedMethods)));

Use PUT to Update a Resource

Następnie zaczniemy przyglądać się PUT, a dokładniej API exchange() dla tej operacji, ponieważ template.put API jest całkiem proste.

7.1. Proste PUT z exchange()

Zaczniemy od prostej operacji PUT przeciwko API – i pamiętaj, że operacja nie zwraca ciała z powrotem do klienta:

Foo updatedInstance = new Foo("newName");updatedInstance.setId(createResponse.getBody().getId());String resourceUrl = fooResourceUrl + '/' + createResponse.getBody().getId();HttpEntity<Foo> requestUpdate = new HttpEntity<>(updatedInstance, headers);template.exchange(resourceUrl, HttpMethod.PUT, requestUpdate, Void.class);

7.2. PUT With exchange() and a Request Callback

Następnie, użyjemy request callback do wykonania PUT.

Upewnijmy się, że przygotowaliśmy callback, gdzie możemy ustawić wszystkie nagłówki, których potrzebujemy, jak również ciało żądania:

RequestCallback requestCallback(final Foo updatedInstance) { return clientHttpRequest -> { ObjectMapper mapper = new ObjectMapper(); mapper.writeValue(clientHttpRequest.getBody(), updatedInstance); clientHttpRequest.getHeaders().add( HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE); clientHttpRequest.getHeaders().add( HttpHeaders.AUTHORIZATION, "Basic " + getBase64EncodedLogPass()); };}

Następnie, tworzymy zasób za pomocą żądania POST:

ResponseEntity<Foo> response = restTemplate .exchange(fooResourceUrl, HttpMethod.POST, request, Foo.class);assertThat(response.getStatusCode(), is(HttpStatus.CREATED));

A następnie aktualizujemy Zasób:

Foo updatedInstance = new Foo("newName");updatedInstance.setId(response.getBody().getId());String resourceUrl =fooResourceUrl + '/' + response.getBody().getId();restTemplate.execute( resourceUrl, HttpMethod.PUT, requestCallback(updatedInstance), clientHttpResponse -> null);

Użyj DELETE aby usunąć Zasób

Aby usunąć istniejący Zasób, szybko użyjemy API delete():

String entityUrl = fooResourceUrl + "/" + existingResource.getId();restTemplate.delete(entityUrl);

Skonfiguruj Timeout

Możemy skonfigurować RestTemplate do przekroczenia limitu czasu poprzez proste użycie ClientHttpRequestFactory:

RestTemplate restTemplate = new RestTemplate(getClientHttpRequestFactory());private ClientHttpRequestFactory getClientHttpRequestFactory() { int timeout = 5000; HttpComponentsClientHttpRequestFactory clientHttpRequestFactory = new HttpComponentsClientHttpRequestFactory(); clientHttpRequestFactory.setConnectTimeout(timeout); return clientHttpRequestFactory;}

I możemy użyć HttpClient dla dalszych opcji konfiguracyjnych:

private ClientHttpRequestFactory getClientHttpRequestFactory() { int timeout = 5000; RequestConfig config = RequestConfig.custom() .setConnectTimeout(timeout) .setConnectionRequestTimeout(timeout) .setSocketTimeout(timeout) .build(); CloseableHttpClient client = HttpClientBuilder .create() .setDefaultRequestConfig(config) .build(); return new HttpComponentsClientHttpRequestFactory(client);}

Podsumowanie

W tym artykule, przeszliśmy przez główne czasowniki HTTP, używając RestTemplate do orkiestracji żądań używających ich wszystkich.

Jeśli chcesz dowiedzieć się, jak przeprowadzić uwierzytelnianie za pomocą szablonu, sprawdź nasz artykuł o Basic Auth with RestTemplate.

Wdrożenie wszystkich tych przykładów i fragmentów kodu można znaleźć na GitHubie.

Zacznij przygodę ze Spring 5 i Spring Boot 2, dzięki kursowi Learn Spring:

>> WYBIERZ KURS

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *