Und wieder guten Tag! Sehr bald werden wir mit dem Training für die nächste Gruppe,
"Developer on the Spring Framework", beginnen , in deren Zusammenhang wir eine offene Lektion durchgeführt haben, die im Vorgriff auf den Start bereits zur Tradition geworden ist. In diesem Webinar haben wir über die Entwicklung von REST-Clients mit Spring gesprochen und uns ausführlich mit Technologien wie Spring Cache, Spring Retry und Hystrix vertraut gemacht.
Dozent:
Yuri Dvorzhetsky - Trainer im Luxoft Training Center, leitender Entwickler, Kandidat für physikalische und mathematische Wissenschaften.
Das Webinar wurde von einem völlig anderen Publikum besucht, das sein Wissen über den Frühling innerhalb von 0 bis 6 Punkten auf einer 10-Punkte-Skala bewertete. Den Bewertungen zufolge schien die offene Lektion jedoch selbst erfahrenen Benutzern nützlich zu sein.
Ein paar Worte zu Spring 5Wie Sie wissen, ist das Spring Framework ein universelles und recht beliebtes Framework für die Java-Plattform. Spring besteht aus einer Masse von Teilprojekten oder Modulen, mit denen Sie viele Probleme lösen können. Tatsächlich handelt es sich hierbei um eine große Sammlung von „Frameworks in einem Framework“, zum Beispiel nur einige davon:
- Spring IoC + AOP = Kontext,
- Frühling JDBC,
- Frühling ORM,
- Spring Data (dies ist eine ganze Reihe von Teilprojekten),
- Spring MVC, Spring WebFlux,
- Frühlingssicherheit
- Spring Cloud (dies ist eine noch größere Menge von Teilprojekten)
- Frühlingscharge,
- Frühlingsstiefel.
Spring ersetzt die Programmierung durch einige Aufgaben zur Konfiguration, aber die Konfiguration wird manchmal nur zu einem Albtraum. Um schnell Anwendungen für die Produktion zu erstellen, verwenden sie
Spring Boot . Dies ist ein spezielles Framework, das eine Reihe von Startern ("Starter") enthält, die die Konfiguration von Spring-Frameworks und anderen Technologien vereinfachen.
Um einige der Merkmale des Frühlings zu zeigen, ist das Thema Blockieren von Websites perfekt, da es jetzt in Mode ist)). Wenn Sie aktiv an der Lektion und Übung teilnehmen möchten, wird empfohlen, das
Repository mit dem vom Lehrer vorgeschlagenen
Servercode herunterzuladen. Wir verwenden den folgenden Befehl:
git clone git@github.com:ydvorzhetskiy/sb-server.git
Führen Sie als Nächstes beispielsweise Folgendes aus:
mvnw spring-boot:run
Die größte Errungenschaft von Spring Boot ist die Möglichkeit, den Server durch einfaches Ausführen der Hauptklasse in IntelliJ IDEA zu starten.
Die Datei BlockedSite.java enthält unseren Quellcode:
package ru.otus.demoserver.domain; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.Id; @Entity public class BlockedSite { @Id @GeneratedValue private int id; private String url;
Und hier ist der Inhalt des BlockedSitesController.java-Controllers:
package ru.otus.demoserver.rest; @RestController public class BlockedSitesController { private final Logger logger = LoggerFactory.getLogger(BlockedSitesController.class); private final BlockedSitesRepository repository; public BlockedSitesController(BlockedSitesRepository repository) { this.repository = repository; } @GetMapping("/blocked-sites") public List<BlockedSite> blockedSites() { logger.info("Request has been performed"); return repository.findAll(); } }
Beachten Sie auch die verschachtelte Datenbank in pom.xml:
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.1.2.RELEASE</version> <relativePath/> </parent> <groupId>ru.otus</groupId> <artifactId>demo-server</artifactId> <version>0.0.1-SNAPSHOT</version> <url>demo-server</url> <description>Demo project for Spring Boot</description> <properties> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <dependency> <groupId>com.h2database</groupId> <artifactId>h2</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
Jetzt speichern wir auf einfache und unprätentiöse Weise zwei blockierte Sites (DemoServerApplication.java) über das Repository in unserer Datenbank:
package ru.otus.demoserver; @SpringBootApplication public class DemoServerApplication { public static void main(String[] args) { ApplicationContext ctx = SpringApplication.run(DemoServerApplication.class, args); BlockedSitesRepository repository = ctx.getBean(BlockedSitesRepository.class); repository.save(new BlockedSite("https://telegram.org/")); repository.save(new BlockedSite("https://azure.microsoft.com/")); } }
Der Server muss noch mit Spring Boot gestartet und die entsprechende URL auf dem lokalen Host geöffnet werden
(localhost:8080/blocked-sites)
. Gleichzeitig sendet unser Server eine Liste der von uns blockierten Sites an uns zurück, dh der Sites, die wir über die Datenbank hinzugefügt haben.
Nun, es ist Zeit, einen Client auf diesen Server zu schreiben. Aber bevor Sie fortfahren, müssen Sie sich an etwas erinnern.
Theoretischer RückzugLassen Sie uns einige HTTP-Methoden (Verben) auflisten:
- GET - Abrufen einer Entität oder Liste;
- POST - Erstellung einer Entität;
- PUT - Entität ändern;
- PATCH - Entitätsänderung (RFC -...);
- LÖSCHEN - Entität löschen;
- HEAD, OPTIONEN - „knifflige“ Methoden zur Unterstützung des HTTP-Protokolls und der REST-Dienste im Allgemeinen;
- TRACE ist eine veraltete Methode, die nicht verwendet wird.
Man kann sich nur an eine so wichtige Eigenschaft wie die
Idempotenz erinnern. In einfachen Worten, unabhängig davon, wie oft Sie eine Operation anwenden, ist das Ergebnis dasselbe, als ob Sie es nur einmal angewendet hätten. Zum Beispiel haben Sie am Morgen einen Mann begrüßt und "Hallo!" Infolgedessen geht Ihr Freund in einen "Hallo" -Zustand :-). Und wenn Sie ihm tagsüber mehrmals „Hallo!“ Sagen, ändert sich nichts, er bleibt im selben Zustand.
Lassen Sie uns nun darüber nachdenken, welche der oben genannten HTTP-Methoden idempotent sind. Natürlich verstehen Sie die Semantik. Wenn Sie es nicht wissen, spricht der Lehrer ab der 26. Minute des Videos ausführlicher darüber.
RUHEUm einen REST-Controller zu schreiben, müssen Sie sich merken, was REST ist:
- REST - Repräsentativer Staatstransfer;
- Es ist ein architektonischer Stil, kein Standard;
- es ist in der Tat eine Reihe von Grundsatzbeschränkungen;
- REST ist lange her, aber der Begriff erschien vor relativ kurzer Zeit;
- Die Webanwendung im REST-Stil heißt RESTful. In diesem Fall ist die API die RESTful-API (das Antonyme lautet Stateful).
- REST heißt jetzt, was immer sie wollen ...
Wenn wir über Interaktion in Form eines Client-Server sprechen, muss diese zunächst in Form einer Anforderungs-Antwort erstellt werden. Ja, die Interaktion ist nicht immer so aufgebaut, aber jetzt ist diese Interaktion sehr häufig, und für Webanwendungen sieht etwas anderes sehr seltsam aus. Aber zum Beispiel Web-Sockets - das ist einfach kein REST.
Zweitens ist die wichtigste Einschränkung bei REST das Fehlen des Clientstatus auf dem Server. Es wird davon ausgegangen, dass der Client bei jeder Anforderung immer den erforderlichen Status an den Server übergibt, dh der Status wird auf der Clientseite gespeichert und es gibt keine Sitzungen auf dem Server.
Wie schreibe ich einen Kunden im Frühjahr
Um fortzufahren, betrachten Sie den Client und führen Sie ihn aus (verwenden Sie den Link zum Repository):
git clone git@github.com:ydvorzhetskiy/sb-client.git
mvnw spring-boot:run
Dies ist eine bereits geschriebene Client- und Konsolenanwendung, kein Webserver.
Wir betrachten die Abhängigkeiten:
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.1.2.RELEASE</version> <relativePath/> </parent> <groupId>ru.otus</groupId> <artifactId>demo-client</artifactId> <version>0.0.1-SNAPSHOT</version> <url>demo-client</url> <description>Demo project for Spring Boot</description> <properties> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> <version>5.1.4.RELEASE</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-annotations</artifactId> <version>2.9.8</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-core</artifactId> <version>2.9.8</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.9.8</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-cache</artifactId> </dependency> <dependency> <groupId>org.springframework.retry</groupId> <artifactId>spring-retry</artifactId> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-hystrix</artifactId> <version>2.0.2.RELEASE</version> </dependency> <dependency> <groupId>com.netflix.hystrix</groupId> <artifactId>hystrix-javanica</artifactId> <version>1.5.12</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
Der Client hat eine Konfiguration:
1. RestTemplateConfig.java
package ru.otus.democlient.config; @Configuration public class RestTemplateConfig { @Bean public RestTemplate restTemplate(RestTemplateBuilder restTemplateBuilder) { return restTemplateBuilder .setConnectTimeout(Duration.ofSeconds(2)) .setReadTimeout(Duration.ofSeconds(3)) .build(); }
2. CacheConfig.java
package ru.otus.democlient.config; @Configuration public class CacheConfig { @Bean public CacheManager cacheManager() { return new ConcurrentMapCacheManager("sites"); } }
Und hier ist der Inhalt der SiteServiceRest.java-Datei:
package ru.otus.democlient.service; import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand; import org.springframework.beans.factory.annotation.Value; import org.springframework.cache.annotation.Cacheable; import org.springframework.core.ParameterizedTypeReference; import org.springframework.http.HttpMethod; import org.springframework.retry.annotation.Backoff; import org.springframework.retry.annotation.Retryable; import org.springframework.stereotype.Service; import org.springframework.web.client.RestTemplate; import java.util.Collections; import java.util.List; @Service public class SiteServiceRest implements SiteService { private final RestTemplate restTemplate; private final String serverUrl; public SiteServiceRest( RestTemplate restTemplate, @Value("${application.server.url}") String serverUrl ) { this.restTemplate = restTemplate; this.serverUrl = serverUrl; } @Override public List<SiteInfo> findAllBlockedSites() { return restTemplate.exchange( serverUrl + "/blocked-sites", HttpMethod.GET, null, new ParameterizedTypeReference<List<SiteInfo>>() { } ).getBody(); } public List<SiteInfo> getDefaultSites() { return Collections.singletonList(new SiteInfo() {{ setUrl("http://vk.com/"); }}); } }
Fassen Sie leicht zusammen:- Anfragen werden über RestTemplate gestellt.
- RestTemplate kann angepasst werden, und dies ist eine normale Bean.
- Jackson wird verwendet, um JSON in Objekte abzubilden.
- Weiter - nur Ihr ausgefallener Flug (Details zum Starten des Clients finden Sie im Video).
Kolleginnen und Kollegen, das Webinar erwies sich als sehr informativ. Um nichts zu verpassen, ist es besser, es vollständig anzusehen. Sie werden die echte API "im Kampf"
@Cacheable
,
@Cacheable
zum Service hinzufügen, mit Spring Retry arbeiten, mehr über Hystrix erfahren und vieles mehr. Wir laden Sie auch zum
Tag der
offenen Tür im Frühling
ein , der sehr bald stattfinden wird.
Und wie immer warten wir auf Ihre Kommentare zur letzten offenen Lektion!