Einstieg in Spring Boot, Teil 20 Webservices mit Spring Boot aufrufen

Von Dr. Dirk Koller |

Als Provider haben wir im vorigen Beitrag dieser Serie einen Webservice zur Verfügung gestellt. Nun schauen wir uns die Gegenseite, den Consumer-Part an. Grundlage ist ein neues unabhängiges Spring-Boot-Projekt mit den Abhängigkeiten Spring Web und Lombok.

Anbieter zum Thema

Spring Boot bietet bewährte Hilfsklassen für den Aufruf und die Verarbeitung von Webservices
Spring Boot bietet bewährte Hilfsklassen für den Aufruf und die Verarbeitung von Webservices
(© monsitj - stock.adobe.com)

Alt aber bewährt: Rest Template

Ähnlich dem JDBC-Template für den Zugriff auf Datenbanken beinhaltet Spring Boot mit dem RestTemplate bewährte Hilfsklassen für den Aufruf und die Verarbeitung von Webservices. Das folgende Beispiel zeigt den Aufruf des im letzten Beitrag erstellten Person-Service. Datenobjekte wie hier die Person müssen sowohl im Consumer- als Provider-Projekt bekannt sein:

RestTemplate restTemplate = new RestTemplate();
String url = "http://localhost:8080/persons/1";
ResponseEntity<Person> personResponse = restTemplate.getForEntity(url, Person.class);
log.info("Person: {}", personResponse.getBody().toString());
log.info("StatusCode: {}", personResponse.getStatusCode().name());
„Spring Boot“-Tutorial
Bildergalerie mit 22 Bildern

Wenn der Statuscode nicht ausgewertet werden soll, kann alternativ auch die Methode getForObject() benutzt werden, man erhält dann direkt das Person-Objekt zurück:

Person person = restTemplate.getForObject(url, Person.class);

Das Anlegen von Ressourcen erfolgt mit einer der post-Methoden:

RestTemplate restTemplate = new RestTemplate();
String url = "http://localhost:8080/persons";
Person person = new Person();
person.setFirstname("Max");
person.setLastname("Mustermann");
HttpEntity<Person> httpEntity = new HttpEntity<>(person);
Person createdPerson = restTemplate.postForObject(url, httpEntity, Person.class);

Die dabei vergebene Location lässt sich mit der Variante postForLocation() in Form eines URI ermitteln:

HttpEntity<Person> httpEntity = new HttpEntity<>(person);
URI location = restTemplate.postForLocation(url, httpEntity);

Ähnlich funktioniert das Aktualisieren von bestehenden Personen mit der RestTemplate-Methode exchange(). Hier wird allerdings zusätzlich die id der zu aktualisierenden Person mitgegeben:

RestTemplate restTemplate = new RestTemplate();
String url = "http://localhost:8080/persons";
Person person = new Person();
person.setFirstname("Another");
person.setLastname("Person");
person.setId(1L);
HttpEntity<Person> httpEntity = new HttpEntity<>(person);
restTemplate.exchange(url, HttpMethod.PUT, httpEntity, Void.class);

Das Löschen schließlich erfolgt mit delete() unter Angabe des URI der zu löschenden Person:

URI location = URI.create("http://localhost:8080/persons/3");
restTemplate.delete(location);

Fast magisch: Feign Client

Zum Rest Template gibt es auch einige Alternativen, die interessanteste darunter ist wohl Feign. Das ursprünglich von Netflix entwickelte Projekt setzt auf einen deklarativen Ansatz und funktioniert ähnlich wie die find-Methoden in JPA-Repositories. Aus dem Namen einer Interface-Methode wird dabei auf den aufzurufenden Webservice geschlossen.

Um Feign nutzen zu können, ist zunächst die folgende Abhängigkeit im Consumer-Projekt einzubinden:

<dependency>
   <groupId>org.springframework.cloud</groupId>
   <artifactId>spring-cloud-starter-openfeign</artifactId>
   <version>3.0.3</version>
</dependency>

Anschließend wird, ebenfalls im Consumer-Projekt, ein Interface angelegt, das den Webservice beschreibt:

@FeignClient(url="localhost:8080", path="/persons", name="PersonClient")
public interface PersonClient {
   @GetMapping(path="/")
   public List<Person> getPersons();
   @GetMapping(path="/{id}")
   public Person getPerson(@PathVariable Long id);
   @DeleteMapping(path="/{id}")
   public void deletePerson(@PathVariable Long id);
   @PostMapping(path="/")
   public void createPerson(@RequestBody Person person);
   @PutMapping(path="/")
   public void updatePerson(@RequestBody Person person);
}

Damit das Interface gefunden wird und als Komponente zur Verfügung steht, fehlt noch die Annotation @EnableFeignClients an der Klasse mit der main-Methode:

@SpringBootApplication
@EnableFeignClients
public class ClientApplication {
   public static void main(String[] args) {
      SpringApplication.run(ClientApplication.class, args);
   }
}

Feign ist nun startklar. Das Interface lässt sich an gewünschter Stelle injizieren und die dort beschriebenen Methoden nutzen:

Person person = new Person();
person.setFirstname("Sonja");
person.setLastname("Sonnig");
personClient.createPerson(person);

Die Zukunft: Web Client

In Spring 5 wurde dem Framework mit dem WebClient ein weiterer RestClient zugefügt. Im Gegensatz zu den beschriebenen Alternativen funktioniert WebClient asynchron, es muss also nicht auf die Antwort des Servers gewartet werden. Wenn diese irgendwann eintrifft, wird sie in einem separaten Thread abgearbeitet.

WebClient ist Teil der Spring WebFlux-Library, diese muss folglich als Dependency eingebunden werden:

<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-webflux</artifactId>
</dependency>

Das folgende Codestück zeigt einen beispielhaften Aufruf. Mit Hilfe der subscribe-Methode registriert sich das Flux-Objekt als Empfänger für die Webservice-Antwort. Diese wird dann im Lambda-Ausdruck abgearbeitet:

URI uri = URI.create("localhost:8080/persons");
Flux<Person> personFlux = WebClient.create()
   .get()
   .uri(uri)
   .retrieve()
   .bodyToFlux(Person.class);
   personFlux.subscribe(person -> log.info(person.toString()));
}

Mit allen vorgestellten Clients lassen sich Webservices aufrufen. Welchen man nun verwendet hängt vom Anwendungsfall ab. RestTemplate ist bewährt und gestattet den Zugriff auf alle Parameter.

Feign ist sehr elegant, bei der Fehlersuche kann es aber knifflig werden. Hier passiert viel hinter den Kulissen. Und für die Freunde des reaktiven Programmierstils bietet sich der neue WebClient an. Da muss dann dann natürlich auch der Rest der Anwendung dazu passen, die asynchron eintrudelnden Daten müssen sinnvoll verarbeitet, also zum Beispiel mithilfe eines Data-Bindings angezeigt werden.

„Spring Boot“-Tutorial
Bildergalerie mit 22 Bildern

(ID:47564065)