Читать книгу Spring Boot - Mark Heckler - Страница 50

Das Utility oder auch: in Aktion »springen«

Оглавление

Setzen wir nun das Repository ein. Ich werde hier wie in den vorangegangenen Kapiteln wieder Schritt für Schritt vorgehen und zunächst die Funktionalität einführen, bevor ich das Ganze dann verfeinere.

Zuerst injiziere ich die Repository-Bean in den RestApiDemoController, damit der Controller darauf zugreifen kann, wenn er Anfragen über das externe API empfängt, wie in Abbildung 4-4 gezeigt.

Zunächst deklariere ich eine Membervariable mit:

private final CoffeeRepository coffeeRepository;

Anschließend füge ich sie dem Konstruktor als Parameter hinzu:

public RestApiDemoController(CoffeeRepository coffeeRepository){}

Vor Spring Framework 4.3 war es in allen Fällen erforderlich, die Annotation @Autowired vor der Methode anzugeben, um anzuzeigen, wenn ein Parameter eine Spring-Bean darstellte, die injiziert/automatisch verdrahtet (autowired) wurde. Seit 4.3 verlangt eine Klasse mit einem einzigen Konstruktor keine Annotation für automatisch verdrahtete Parameter mehr, was eine schöne Zeitersparnis ist.

Abbildung 4-4: Einfügen des Repository in »RestApiDemoController«

Wenn das Repository an Ort und Stelle ist, lösche ich die Membervariable List <Coffee> und ändere die Anfangsbelegung dieser Liste im Konstruktor, um die Kaffees nun im Repository zu speichern, wie in Abbildung 4-4 gezeigt.

Wie Sie in Abbildung 4-5 sehen, werden beim Entfernen der coffees-Variablen sofort alle Referenzen darauf als unauflösbare Symbole angezeigt, sodass die nächste Aufgabe darin besteht, diese durch die entsprechenden Repository-Interaktionen zu ersetzen.

Abbildung 4-5: Ersetzen der gelöschten »coffees«-Membervariablen

Als einfache Abfrage aller Kaffees ohne Parameter ist die Methode getCoffees() ein guter Startpunkt. Wenn Sie die findAll()-Methode verwenden, die in CrudRepository eingebaut ist, müssen Sie nicht einmal den Rückgabetyp von getCoffees() ändern, da dies einen Iterable-Typ zurückliefert; ein einfaches Aufrufen von coffee Repository.findAll() und Zurückgeben des Ergebnisses reicht völlig aus, wie hier zu sehen ist:

@GetMapping

Iterable<Coffee> getCoffees() {

return coffeeRepository.findAll();

}

Das Refaktorieren der Methode getCoffeeById() liefert uns einige Einblicke, wie viel einfacher Ihr Code dank der Funktionalität sein kann, die das Repository mitbringt. Wir müssen die Liste der Kaffees nicht mehr manuell nach einer passenden id durchsuchen, die findById()-Methode von CrudRepository erledigt das für uns, wie der folgende Codeausschnitt beweist. Und da findById() einen Optional-Typ zurückliefert, sind für unsere Methodensignatur überhaupt keine Änderungen erforderlich:

@GetMapping("/{id}")

Optional<Coffee> getCoffeeById(@PathVariable String id) {

return coffeeRepository.findById(id);

}

Das Konvertieren der Methode postCoffee() für die Benutzung des Repository ist ebenfalls eine relativ einfache Angelegenheit:

@PostMapping

Coffee postCoffee(@RequestBody Coffee coffee) {

return coffeeRepository.save(coffee);

}

Die Methode putCoffee() demonstriert uns erneut die zeit- und codesparende Funktionalität von CrudRepository. Ich verwende die eingebaute existsById()-Repository-Methode, um festzustellen, ob dies ein neuer oder ein bereits vorhandener Coffee ist, und gebe zusammen mit dem gespeicherten Coffee den passenden HTTP-Statuscode zurück, wie dieses Listing zeigt:

@PutMapping("/{id}")

ResponseEntity<Coffee> putCoffee(@PathVariable String id,

@RequestBody Coffee coffee) {

return (!coffeeRepository.existsById(id))

? new ResponseEntity<>(coffeeRepository.save(coffee),

HttpStatus.CREATED)

: new ResponseEntity<>(coffeeRepository.save(coffee), HttpStatus.OK);

}

Schließlich aktualisiere ich die Methode deleteCoffee() so, dass sie nun die in Crud Repository eingebaute deleteById()-Methode benutzt:

@DeleteMapping("/{id}")

void deleteCoffee(@PathVariable String id) {

coffeeRepository.deleteById(id);

}

Das Einsetzen einer Repository-Bean, die mit dem »sprechenden« API von Crud Repository erzeugt wurde, glättet den Code für den RestApiDemoController und macht ihn viel lesbarer und verständlicher, wie das komplette Listing beweist:

@RestController

@RequestMapping("/coffees")

class RestApiDemoController {

private final CoffeeRepository coffeeRepository;

public RestApiDemoController(CoffeeRepository coffeeRepository) {

this.coffeeRepository = coffeeRepository;

this.coffeeRepository.saveAll(List.of(

new Coffee("Café Cereza"),

new Coffee("Café Ganador"),

new Coffee("Café Lareño"),

new Coffee("Café Três Pontas")

));

}

@GetMapping

Iterable<Coffee> getCoffees() {

return coffeeRepository.findAll();

}

@GetMapping("/{id}")

Optional<Coffee> getCoffeeById(@PathVariable String id) {

return coffeeRepository.findById(id);

}

@PostMapping

Coffee postCoffee(@RequestBody Coffee coffee) {

return coffeeRepository.save(coffee);

}

@PutMapping("/{id}")

ResponseEntity<Coffee> putCoffee(@PathVariable String id,

@RequestBody Coffee coffee) {

return (!coffeeRepository.existsById(id))

? new ResponseEntity<>(coffeeRepository.save(coffee),

HttpStatus.CREATED)

: new ResponseEntity<>(coffeeRepository.save(coffee), HttpStatus.OK);

}

@DeleteMapping("/{id}")

void deleteCoffee(@PathVariable String id) {

coffeeRepository.deleteById(id);

}

}

Nun müssen wir nur noch verifizieren, dass unsere Anwendung erwartungsgemäß arbeitet und die externe Funktionalität gleich geblieben ist.

Eine alternative Vorgehensweise zum Testen der Funktionalität – und eine empfohlene Praxis – ist es, zuerst Unit-Tests herzustellen, also im Sinne einer Test-driven Development (TDD; testgetriebene Entwicklung) zu arbeiten. Ich rate Ihnen unbedingt, bei realen Softwareentwicklungen so vorzugehen, habe aber festgestellt, dass beim Demonstrieren und Erklären einzelner Entwicklungskonzepte weniger durchaus mehr ist. Deshalb zeige ich nur das Nötigste, wenn ich wichtige Konzepte vermitteln möchte, und gehe auf das Testen in einem eigenen Kapitel weiter hinten in diesem Buch ein.
Spring Boot

Подняться наверх