JavaRush /Blog Java /Random-PL /Przegląd ODPOCZYNKU. Część 3: Tworzenie usługi RESTful w ...

Przegląd ODPOCZYNKU. Część 3: Tworzenie usługi RESTful w Spring Boot

Opublikowano w grupie Random-PL
To jest ostatnia część analizy REST. W poprzednich częściach: Przegląd ODPOCZYNKU.  Część 3: Tworzenie usługi RESTful w Spring Boot — 1

Tworzenie projektu

W tej sekcji utworzymy małą aplikację RESTful przy użyciu Spring Boot. Nasza aplikacja zaimplementuje na klientach operacje CRUD (Create, Read, Update, Delete) z przykładu z ostatniej części analizy. Najpierw utwórzmy nową aplikację Spring Boot za pomocą menu Plik -> Nowy -> Projekt... W oknie, które zostanie otwarte, wybierz Spring Individualizr i określ Project SDK: Przegląd ODPOCZYNKU.  Część 3: Tworzenie usługi RESTful w Spring Boot — 2Kliknij przycisk Dalej. W następnym oknie określ typ projektu Maven, określ Grupę i Artefakt: Przegląd ODPOCZYNKU.  Część 3: Tworzenie usługi RESTful w Spring Boot — 3Kliknij przycisk Dalej. W kolejnym oknie musimy wybrać komponenty Spring Framework potrzebne do realizacji projektu. Wystarczy nam Spring Web: Przegląd ODPOCZYNKU.  Część 3: Tworzenie usługi RESTful w Spring Boot — 4Kliknij przycisk Dalej. Następnie pozostaje już tylko określić nazwę projektu i jego lokalizację w systemie plików: Przegląd ODPOCZYNKU.  Część 3: Tworzenie usługi RESTful w Spring Boot — 5Kliknij przycisk Zakończ. Projekt został stworzony, teraz możemy zobaczyć jego strukturę: Przegląd ODPOCZYNKU.  Część 3: Tworzenie usługi RESTful w Spring Boot — 6IDEA wygenerowała dla nas deskryptor wdrażania systemu Maven build - pom.xml oraz główną klasę aplikacji: RestExampleApplication. Oto ich kod:
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 https://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.2.2.RELEASE</version>
       <relativePath/> <!-- lookup parent from repository -->
   </parent>
   <groupId>com.javarush.lectures</groupId>
   <artifactId>rest_example</artifactId>
   <version>0.0.1-SNAPSHOT</version>
   <name>rest_example</name>
   <description>REST example project</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-test</artifactId>
           <scope>test</scope>
           <exclusions>
               <exclusion>
                   <groupId>org.junit.vintage</groupId>
                   <artifactId>junit-vintage-engine</artifactId>
               </exclusion>
           </exclusions>
       </dependency>
   </dependencies>

   <build>
       <plugins>
           <plugin>
               <groupId>org.springframework.boot</groupId>
               <artifactId>spring-boot-maven-plugin</artifactId>
           </plugin>
       </plugins>
   </build>

</project>
ResztaPrzykładowa aplikacja:
@SpringBootApplication
public class RestExampleApplication {

   public static void main(String[] args) {
       SpringApplication.run(RestExampleApplication.class, args);
   }

}

Tworzenie funkcjonalności REST

Nasza aplikacja zarządza klientami. Pierwszą rzeczą, którą musimy zrobić, to utworzyć encję klienta. Będą to zajęcia POJO. Stwórzmy pakiet modelwewnątrz pakietu com.javarush.lectures.rest_example. modelStwórzmy klasę wewnątrz pakietu Client:
public class Client {

   private Integer id;
   private String name;
   private String email;
   private String phone;

   public Integer getId() {
       return id;
   }

   public void setId(Integer id) {
       this.id = id;
   }

   public String getName() {
       return name;
   }

   public void setName(String name) {
       this.name = name;
   }

   public String getEmail() {
       return email;
   }

   public void setEmail(String email) {
       this.email = email;
   }

   public String getPhone() {
       return phone;
   }

   public void setPhone(String phone) {
       this.phone = phone;
   }
}
Usługa zaimplementuje operacje CRUD na kliencie. Kolejnym krokiem jest stworzenie usługi, która zaimplementuje te operacje. W pakiecie com.javarush.lectures.rest_exampleutworzymy pakiet service, wewnątrz którego utworzymy interfejs ClientService. Oto kod interfejsu z komentarzami:
public interface ClientService {

   /**
    * Создает нового клиента
    * @param client - клиент для создания
    */
   void create(Client client);

   /**
    * zwroty список всех имеющихся клиентов
    * @return список клиентов
    */
   List<client> readAll();

   /**
    * zwroty клиента по его ID
    * @param id - ID клиента
    * @return - obiekt клиента с заданным ID
    */
   Client read(int id);

   /**
    * Обновляет клиента с заданным ID,
    * в соответствии с переданным клиентом
    * @param client - клиент в соответсвии с которым нужно обновить данные
    * @param id - id клиента которого нужно обновить
    * @return - true если данные были обновлены, иначе false
    */
   boolean update(Client client, int id);

   /**
    * Удаляет клиента с заданным ID
    * @param id - id клиента, которого нужно удалить
    * @return - true если клиент был удален, иначе false
    */
   boolean delete(int id);
}
Następnie musimy stworzyć implementację tego interfejsu. Teraz będzie działać jako repozytorium klientów Map<Integer, Client>. Kluczem karty będzie identyfikator klienta, a wartością będzie sam klient. Dokonano tego, aby nie przeciążać przykładu specyfiką pracy z bazą danych. Jednak w przyszłości będziemy mogli napisać kolejną implementację interfejsu, w którym możliwe będzie podłączenie prawdziwej bazy danych. W pakiecie servicestworzymy implementację interfejsu ClientService:
@Service
public class ClientServiceImpl implements ClientService {

   // ХранLubще клиентов
   private static final Map<Integer, Client> CLIENT_REPOSITORY_MAP = new HashMap<>();

   // Переменная для генерации ID клиента
   private static final AtomicInteger CLIENT_ID_HOLDER = new AtomicInteger();

   @Override
   public void create(Client client) {
       final int clientId = CLIENT_ID_HOLDER.incrementAndGet();
       client.setId(clientId);
       CLIENT_REPOSITORY_MAP.put(clientId, client);
   }

   @Override
   public List<Client> readAll() {
       return new ArrayList<>(CLIENT_REPOSITORY_MAP.values());
   }

   @Override
   public Client read(int id) {
       return CLIENT_REPOSITORY_MAP.get(id);
   }

   @Override
   public boolean update(Client client, int id) {
       if (CLIENT_REPOSITORY_MAP.containsKey(id)) {
           client.setId(id);
           CLIENT_REPOSITORY_MAP.put(id, client);
           return true;
       }

       return false;
   }

   @Override
   public boolean delete(int id) {
       return CLIENT_REPOSITORY_MAP.remove(id) != null;
   }
}
Adnotacja @Servicemówi Springowi, że ta klasa jest usługą. Jest to specjalny typ klasy, w którym zaimplementowana jest pewna logika biznesowa aplikacji. Następnie, dzięki tej adnotacji, Spring udostępni nam instancję tej klasy tam, gdzie jest to potrzebne, za pomocą Zastrzyku zależności. Teraz czas na utworzenie kontrolera. Specjalna klasa, w której implementujemy logikę przetwarzania żądań klientów dla punktów końcowych (URI). Aby było jaśniej, utworzymy tę klasę w częściach. Najpierw utwórzmy samą klasę i wprowadźmy od niej zależność ClientService:
@RestController
public class ClientController {

   private final ClientService clientService;

   @Autowired
   public ClientController(ClientService clientService) {
       this.clientService = clientService;
   }
}
Wyjaśnijmy adnotacje: @RestController – informuje Springa, że ​​ta klasa jest kontrolerem REST. Te. ta klasa zaimplementuje logikę przetwarzania żądań klientów @Autowired - mówi Springowi, że w tym miejscu należy wstrzyknąć zależność. Przekazujemy interfejs konstruktorowi ClientService. Implementację tej usługi oznaczyliśmy wcześniej adnotacją @Service, a teraz Spring będzie mógł przekazać instancję tej implementacji do konstruktora kontrolera. Następnie krok po kroku zaimplementujemy każdą metodę kontrolera do przetwarzania operacji CRUD. Zacznijmy od operacji Utwórz. Aby to zrobić, napiszmy metodę create:
@PostMapping(value = "/clients")
public ResponseEntity<?> create(@RequestBody Client client) {
   clientService.create(client);
   return new ResponseEntity<>(HttpStatus.CREATED);
}
Przyjrzyjmy się tej metodzie: @PostMapping(value = "/clients")- tutaj mamy na myśli, że metoda ta przetwarza żądania POST na adres /clients Metoda zwraca ResponseEntity<?>. ResponseEntity- specjalna klasa do zwracania odpowiedzi. Za jego pomocą możemy później zwrócić klientowi kod stanu HTTP. Metoda pobiera parametr @RequestBody Client client, wartość tego parametru jest zastępowana z treści żądania. Streszczenie o tym mówi @RequestBody. Wewnątrz treści metody wywołujemy metodę create na wcześniej utworzonej usłudze i przekazujemy ją kontrolerowi klienta zaakceptowanemu w parametrach. Następnie zwracamy status 201 Utworzono tworząc nowy obiekt ResponseEntityi przekazując mu wymaganą wartość wyliczeniową HttpStatus. Następnie realizujemy operację Read: W pierwszej kolejności realizujemy operację uzyskania listy wszystkich dostępnych klientów:
@GetMapping(value = "/clients")
public ResponseEntity<List<Client>> read() {
   final List<Client> clients = clientService.readAll();

   return clients != null &&  !clients.isEmpty()
           ? new ResponseEntity<>(clients, HttpStatus.OK)
           : new ResponseEntity<>(HttpStatus.NOT_FOUND);
}
Zacznijmy analizę: @GetMapping(value = "/clients")- wszystko jest podobnie jak w adnotacji @PostMapping, tylko teraz przetwarzamy żądania GET. Tym razem wracamy ResponseEntity<List<Client>>, tylko tym razem oprócz statusu HTTP zwrócimy także treść odpowiedzi, którą będzie lista klientów. W kontrolerach Spring REST wszystkie obiekty POJO, a także kolekcje obiektów POJO zwracane jako treści odpowiedzi, są automatycznie serializowane do formatu JSON, chyba że wyraźnie określono inaczej. To nam całkiem odpowiada. Wewnątrz metody, korzystając z naszej usługi, otrzymujemy listę wszystkich klientów. Następnie, jeśli lista nie jest pusta lub ma wartość null, za pomocą klasy zwracamy ResponseEntitylistę klientów i status HTTP 200 OK. W przeciwnym razie po prostu zwracamy status HTTP 404 Nie znaleziono. Następnie zaimplementujemy możliwość odbioru klienta po jego id:
@GetMapping(value = "/clients/{id}")
public ResponseEntity<Client> read(@PathVariable(name = "id") int id) {
   final Client client = clientService.read(id);

   return client != null
           ? new ResponseEntity<>(client, HttpStatus.OK)
           : new ResponseEntity<>(HttpStatus.NOT_FOUND);
}
Nowością jest to, że mamy teraz zmienną ścieżki. Zmienna zdefiniowana w identyfikatorze URI. value = "/clients/{id}". Zaznaczyliśmy to w nawiasach klamrowych. Natomiast w parametrach metody przyjmujemy ją jako intzmienną korzystając z adnotacji @PathVariable(name = "id"). Metoda ta akceptuje żądania uri w postaci /clients/{id}, gdzie zamiast tego {id}może występować dowolna wartość liczbowa. Wartość ta jest następnie przekazywana do zmiennej int id— parametru metody. W ciele odbieramy przedmiot Clientkorzystając z naszej usługi i akceptujemy go id. I wtedy analogicznie do listy zwracamy albo status 200 OK i sam obiekt Client, albo po prostu status 404 Not Found, jeśli idw systemie nie ma klienta z tym. Pozostaje wdrożyć dwie operacje - Aktualizuj i Usuń. Oto kod tych metod:
@PutMapping(value = "/clients/{id}")
public ResponseEntity<?> update(@PathVariable(name = "id") int id, @RequestBody Client client) {
   final boolean updated = clientService.update(client, id);

   return updated
           ? new ResponseEntity<>(HttpStatus.OK)
           : new ResponseEntity<>(HttpStatus.NOT_MODIFIED);
}

@DeleteMapping(value = "/clients/{id}")
public ResponseEntity<?> delete(@PathVariable(name = "id") int id) {
   final boolean deleted = clientService.delete(id);

   return deleted
           ? new ResponseEntity<>(HttpStatus.OK)
           : new ResponseEntity<>(HttpStatus.NOT_MODIFIED);
}
W metodach tych nie ma w zasadzie nic nowego, dlatego pominiemy szczegółowy opis. Jedyną rzeczą wartą wspomnienia jest to, że metoda updateprzetwarza żądania PUT (adnotacja @PutMapping), a metoda deleteprzetwarza żądania DELETE (adnotacja DeleteMapping). Oto pełny kod kontrolera:
@RestController
public class ClientController {

   private final ClientService clientService;

   @Autowired
   public ClientController(ClientService clientService) {
       this.clientService = clientService;
   }

   @PostMapping(value = "/clients")
   public ResponseEntity<?> create(@RequestBody Client client) {
       clientService.create(client);
       return new ResponseEntity<>(HttpStatus.CREATED);
   }

   @GetMapping(value = "/clients")
   public ResponseEntity<List<Client>> read() {
       final List<client> clients = clientService.readAll();

       return clients != null &&  !clients.isEmpty()
               ? new ResponseEntity<>(clients, HttpStatus.OK)
               : new ResponseEntity<>(HttpStatus.NOT_FOUND);
   }

   @GetMapping(value = "/clients/{id}")
   public ResponseEntity<Client> read(@PathVariable(name = "id") int id) {
       final Client client = clientService.read(id);

       return client != null
               ? new ResponseEntity<>(client, HttpStatus.OK)
               : new ResponseEntity<>(HttpStatus.NOT_FOUND);
   }

   @PutMapping(value = "/clients/{id}")
   public ResponseEntity<?> update(@PathVariable(name = "id") int id, @RequestBody Client client) {
       final boolean updated = clientService.update(client, id);

       return updated
               ? new ResponseEntity<>(HttpStatus.OK)
               : new ResponseEntity<>(HttpStatus.NOT_MODIFIED);
   }

   @DeleteMapping(value = "/clients/{id}")
   public ResponseEntity<?> delete(@PathVariable(name = "id") int id) {
       final boolean deleted = clientService.delete(id);

       return deleted
               ? new ResponseEntity<>(HttpStatus.OK)
               : new ResponseEntity<>(HttpStatus.NOT_MODIFIED);
   }
}
W rezultacie struktura naszego projektu wygląda następująco: Przegląd ODPOCZYNKU.  Część 3: Tworzenie usługi RESTful w Spring Boot — 7

Uruchom i przetestuj

Aby uruchomić naszą aplikację wystarczy uruchomić metodę mainw klasie RestExampleApplication. Aby przetestować usługi internetowe RESTful, musisz pobrać nowe oprogramowanie) Faktem jest, że żądania GET można dość łatwo wysłać ze zwykłej przeglądarki, ale w przypadku POST, PUT i DELETE zwykła przeglądarka nie wystarczy. Nie martw się: możesz używać Postmana do wysyłania dowolnych żądań HTTP. Możesz go pobrać stąd . Po pobraniu i zainstalowaniu przystępujemy do testowania naszej aplikacji. W tym celu otwórz program i utwórz nowe zgłoszenie: Przegląd ODPOCZYNKU.  Część 3: Tworzenie usługi RESTful w Spring Boot — 9Kliknij przycisk Nowy w lewym górnym rogu. Następnie wybierz opcję Żądanie: Обзор REST. Часть 3: создание RESTful сервиса на Spring Boot - 10Następnie nadaj mu nazwę i zapisz. Spróbujmy teraz wysłać żądanie POST do serwera i utworzyć pierwszego klienta: Обзор REST. Часть 3: создание RESTful сервиса на Spring Boot - 11Tworzymy w ten sposób kilku klientów. Następnie zmieniamy typ żądania na GET i wysyłamy je do serwera: Обзор REST. Часть 3: создание RESTful сервиса на Spring Boot - 12

Wyniki ogólne

Gratulacje: omówiliśmy całkiem sporo tematu REST. Cały materiał okazał się obszerny, ale mamy nadzieję, że będzie dla Ciebie przydatny:
  1. Dowiedzieliśmy się, czym jest REST.

  2. Zapoznaliśmy się z historią REST.

  3. Rozmawialiśmy o ograniczeniach i zasadach tego stylu architektonicznego:

    • doprowadzenie architektury do modelu klient-serwer;
    • brak kondycji;
    • buforowanie;
    • jednolitość interfejsu;
    • warstwy;
    • kod na żądanie (ograniczenie opcjonalne).
  4. Sprawdziliśmy zalety, jakie zapewnia REST

  5. Szczegółowo zbadaliśmy, w jaki sposób serwer i klient współdziałają ze sobą za pomocą protokołu HTTP.

  6. Przyjrzyjmy się bliżej prośbom i odpowiedziom. Ich elementy zostały zdemontowane.

  7. Na koniec przeszliśmy do ćwiczeń i napisaliśmy własną małą aplikację RESTful w Spring Boot. Dowiedzieliśmy się nawet, jak to przetestować za pomocą programu Postman.

Uff. Okazało się, że jest obszerne, ale mimo to jest coś do zrobienia jako praca domowa.

Praca domowa

Spróbuj wykonać następujące czynności:
  1. Kierując się powyższym opisem, utwórz własny projekt Spring Boot i zaimplementuj w nim tę samą logikę, co na wykładzie. Powtórz wszystko 1 w 1.
  2. Uruchom to. aplikacja.
  3. Pobierz i skonfiguruj Postmana (lub dowolne inne narzędzie do wysyłania żądań, nawet curl).
  4. Przetestuj żądania POST i GET w taki sam sposób, jak opisano w wykładzie.
  5. Przetestuj samodzielnie żądania PUT i DELETE.
Część 1: Co to jest REST Część 2: Komunikacja pomiędzy klientem a serwerem
Komentarze
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION