JavaRush /בלוג Java /Random-HE /סקירה כללית של REST. חלק 3: יצירת שירות רגוע באביב אתחול

סקירה כללית של REST. חלק 3: יצירת שירות רגוע באביב אתחול

פורסם בקבוצה
זהו החלק האחרון של ניתוח REST. בחלקים הקודמים: סקירה כללית של REST.  חלק 3: יצירת שירות רגוע במתחול האביב - 1

יצירת פרויקט

בחלק זה, ניצור יישום קטן של RESTful באמצעות Spring Boot. האפליקציה שלנו תטמיע פעולות CRUD (צור, קרא, עדכן, מחק) על לקוחות מהדוגמה מהחלק האחרון של הניתוח. ראשית, בואו ניצור אפליקציית Spring Boot חדשה דרך התפריט File -> New -> Project... בחלון שנפתח, בחר Spring Initializr וציין Project SDK: סקירה כללית של REST.  חלק 3: יצירת שירות רגוע באתחול אביב - 2לחץ על כפתור Next. בחלון הבא, ציין את סוג הפרויקט של Maven, ציין קבוצה ו-Artifact: סקירה כללית של REST.  חלק 3: יצירת שירות רגוע באתחול אביב - 3לחץ על הלחצן הבא. בחלון הבא, עלינו לבחור את רכיבי Spring Framework הדרושים לפרויקט. אינטרנט אביב יספיק לנו: סקירה כללית של REST.  חלק 3: יצירת שירות רגוע באתחול אביב - 4לחץ על הלחצן הבא. לאחר מכן, כל שנותר הוא לציין את שם הפרויקט ומיקומו במערכת הקבצים: סקירה כללית של REST.  חלק 3: יצירת שירות רגוע במתחול האביב - 5לחצו על כפתור סיום. הפרויקט נוצר, כעת אנו יכולים לראות את המבנה שלו: סקירה כללית של REST.  חלק 3: יצירת שירות רגוע במתחול אביב - 6IDEA יצרה עבורנו את מתאר פריסת מערכת ה-Maven build - pom.xml ואת מחלקת היישומים הראשית: RestExampleApplication. הנה הקוד שלהם:
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>
RestExampleApplication:
@SpringBootApplication
public class RestExampleApplication {

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

}

יצירת פונקציונליות REST

האפליקציה שלנו מנהלת לקוחות. אז הדבר הראשון שעלינו לעשות הוא ליצור ישות לקוחה. זה יהיה שיעור POJO. בואו ניצור חבילה modelבתוך חבילה com.javarush.lectures.rest_example. modelבואו ניצור מחלקה בתוך החבילה 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;
   }
}
השירות יישם פעולות CRUD על הלקוח. השלב הבא הוא יצירת שירות שיטמיע את הפעולות הללו. בחבילה com.javarush.lectures.rest_exampleניצור חבילה serviceשבתוכה ניצור ממשק ClientService. הנה קוד הממשק עם הערות:
public interface ClientService {

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

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

   /**
    * returns клиента по его ID
    * @param id - ID клиента
    * @return - an object клиента с заданным 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);
}
בשלב הבא עלינו ליצור יישום של ממשק זה. כעת הוא יפעל כמאגר לקוחות Map<Integer, Client>. מפתח הכרטיס יהיה מזהה הלקוח, והערך יהיה הלקוח עצמו. זה נעשה כדי לא להעמיס על הדוגמה בפרטי העבודה עם מסד הנתונים. עם זאת, בעתיד נוכל לכתוב יישום נוסף של הממשק בו ניתן יהיה לחבר בסיס נתונים אמיתי. בחבילה serviceניצור יישום של הממשק ClientService:
@Service
public class ClientServiceImpl implements ClientService {

   // Хранorще клиентов
   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;
   }
}
ההערה @Serviceאומרת לאביב שהשיעור הזה הוא שירות. זהו סוג מיוחד של מחלקה שבה מיושמת היגיון עסקי כלשהו של האפליקציה. לאחר מכן, הודות להערה זו, Spring תספק לנו מופע של מחלקה זו במקומות שבהם הוא נחוץ באמצעות Dependency Injection. עכשיו הגיע הזמן ליצור את הבקר. מחלקה מיוחדת בה אנו מיישמים את ההיגיון לעיבוד בקשות לקוח עבור נקודות קצה (URI). כדי להבהיר את זה, ניצור את המחלקה הזו בחלקים. ראשית, בואו ניצור את המחלקה עצמה ונציג בה תלות ClientService:
@RestController
public class ClientController {

   private final ClientService clientService;

   @Autowired
   public ClientController(ClientService clientService) {
       this.clientService = clientService;
   }
}
בואו נבהיר את ההערות: @RestController - אומר ל-Spring שהמחלקה הזו היא בקר REST. הָהֵן. מחלקה זו תטמיע את ההיגיון לעיבוד בקשות לקוח @Autowired - אומר ל-Spring שצריך להחדיר תלות במקום הזה. אנו מעבירים את הממשק לבנאי ClientService. סימנו את היישום של שירות זה עם הערה @Serviceקודם לכן, וכעת Spring יוכל להעביר מופע של יישום זה לבנאי הבקר. בשלב הבא ניישם כל שיטת בקר לעיבוד פעולות CRUD, צעד אחר צעד. נתחיל בפעולת היצירה. לשם כך, בוא נכתוב שיטה create:
@PostMapping(value = "/clients")
public ResponseEntity<?> create(@RequestBody Client client) {
   clientService.create(client);
   return new ResponseEntity<>(HttpStatus.CREATED);
}
בואו נסתכל על השיטה הזו: @PostMapping(value = "/clients")- כאן אנחנו מתכוונים ששיטה זו מעבדת בקשות POST לכתובת /clients השיטה מחזירה ResponseEntity<?>. ResponseEntity- שיעור מיוחד להחזרת תשובות. באמצעותו נוכל להחזיר מאוחר יותר את קוד סטטוס ה-HTTP ללקוח. השיטה לוקחת פרמטר @RequestBody Client client, הערך של פרמטר זה מוחלף מגוף הבקשה. התקציר מדבר על זה @RequestBody. בתוך גוף השיטה, אנו קוראים לשיטת create בשירות שנוצר קודם לכן ומעבירים לה את בקר הלקוח המקובל בפרמטרים. לאחר מכן אנו מחזירים את הסטטוס 201 נוצר על ידי יצירת אובייקט חדש ResponseEntityוהעברת ערך ה-enum הנדרש אליו HttpStatus. לאחר מכן, אנו מיישמים את הפעולה Read: ראשית, אנו מיישמים את פעולת השגת רשימה של כל הלקוחות הזמינים:
@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")- הכל דומה להערה @PostMapping, רק עכשיו אנחנו מעבדים בקשות GET. הפעם נחזיר ResponseEntity<List<Client>>, רק שהפעם בנוסף לסטטוס HTTP נחזיר גם את גוף התגובה שיהיה רשימת לקוחות. בבקרי Spring REST, כל אובייקטי POJO, כמו גם אוספים של אובייקטי POJO המוחזרים כגופי תגובה, עוברים באופן אוטומטי בסידרה ל-JSON אלא אם צוין אחרת במפורש. אנחנו די מרוצים מזה. בתוך השיטה, באמצעות השירות שלנו, אנו מקבלים רשימה של כל הלקוחות. לאחר מכן, אם הרשימה אינה אפסית או ריקה, אנו מחזירים ResponseEntityאת רשימת הלקוחות ואת מצב ה-HTTP 200 אישור באמצעות המחלקה. אחרת, אנחנו פשוט מחזירים את סטטוס HTTP 404 לא נמצא. לאחר מכן, ניישם את היכולת להשיג לקוח לפי המזהה שלו:
@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);
}
משהו חדש הוא שכעת יש לנו משתנה נתיב. משתנה המוגדר ב-URI. value = "/clients/{id}". ציינו זאת בפלטה מתולתלת. ובפרמטרים של השיטה אנו מקבלים אותו כמשתנה intבאמצעות ההערה @PathVariable(name = "id"). שיטה זו תקבל בקשות עבור uri של הטופס /clients/{id}, כאשר במקום זאת {id}יכול להיות כל ערך מספרי. ערך זה מועבר לאחר מכן למשתנה int id- פרמטר השיטה. בגוף אנו מקבלים את החפץ Clientבאמצעות השירות שלנו ומתקבל id. ואז, באנלוגיה לרשימה, אנו מחזירים או את מצב 200 אישור ואת האובייקט עצמו Client, או פשוט את סטטוס 404 לא נמצא, אם אין idלקוח עם זה במערכת. נותר ליישם שתי פעולות - עדכון ומחיקה. להלן הקוד לשיטות אלו:
@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);
}
אין שום דבר חדש במהותו בשיטות אלו, אז נדלג על תיאור מפורט. הדבר היחיד שכדאי להזכיר הוא שהשיטה updateמעבדת בקשות PUT (ביאור @PutMapping), והשיטה deleteמעבדת בקשות DELETE (ביאור DeleteMapping). להלן קוד הבקר המלא:
@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);
   }
}
כתוצאה מכך, המבנה של הפרויקט שלנו נראה כך: סקירה כללית של REST.  חלק 3: יצירת שירות רגוע במתחול האביב - 7

השקה ובדיקה

כדי להפעיל את האפליקציה שלנו, פשוט הפעל את השיטה mainבמחלקה RestExampleApplication. וכדי לבדוק שירותי אינטרנט של RESTful, צריך להוריד תוכנה חדשה) העובדה היא שבקשות GET די קלות לשלוח מדפדפן רגיל, אבל עבור POST, PUT ו-DELETE לא מספיק דפדפן רגיל. אל תדאג: אתה יכול להשתמש ב-Postman כדי לשלוח כל בקשות HTTP. אתה יכול להוריד אותו מכאן . לאחר ההורדה וההתקנה, אנו מתחילים לבדוק את האפליקציה שלנו. לשם כך, פתח את התוכנית וצור בקשה חדשה: סקירה כללית של REST.  חלק 3: יצירת שירות רגוע במתחול האביב - 9לחץ על כפתור חדש בפינה השמאלית העליונה. לאחר מכן, בחר בקש: Обзор REST. Часть 3: создание RESTful сервиса на Spring Boot - 10הבא, תן לו שם ושמור אותו. כעת ננסה לשלוח בקשת POST לשרת וליצור את הלקוח הראשון: Обзор REST. Часть 3: создание RESTful сервиса на Spring Boot - 11אנו יוצרים מספר לקוחות בצורה זו. לאחר מכן אנו משנים את סוג הבקשה ל-GET ושולחים אותו לשרת: Обзор REST. Часть 3: создание RESTful сервиса на Spring Boot - 12

תוצאות כלליות

מזל טוב: כיסינו לא מעט את הנושא של REST. כל החומר התברר כנפח, אבל אנו מקווים שהוא יהיה שימושי עבורך:
  1. למדנו מה זה REST.

  2. התוודענו להיסטוריה של REST.

  3. דיברנו על המגבלות והעקרונות של סגנון אדריכלי זה:

    • הבאת הארכיטקטורה למודל שרת-לקוח;
    • חוסר מצב;
    • מטמון;
    • אחידות הממשק;
    • שכבות;
    • קוד לפי דרישה (הגבלה אופציונלית).
  4. בדקנו את היתרונות שמספקת REST

  5. בדקנו בפירוט כיצד השרת והלקוח מתקשרים זה עם זה באמצעות פרוטוקול HTTP.

  6. בואו נסתכל מקרוב על הבקשות והתגובות. הרכיבים שלהם פורקו.

  7. לבסוף, עברנו לתרגול וכתבנו יישום קטן משלנו RESTful ב-Spring Boot. ואפילו למדנו איך לבדוק את זה באמצעות תוכנית Postman.

פיו. זה התברר כנפח, אבל בכל זאת יש מה לעשות כמו שיעורי בית.

שיעורי בית

נסה את הפעולות הבאות:
  1. בעקבות התיאור למעלה, צור פרויקט Spring Boot משלך והטמיע בו את אותו ההיגיון כמו בהרצאה. חזור על הכל 1 ב-1.
  2. הפעל אותו. יישום.
  3. הורד והגדר את Postman (או כל כלי אחר לשליחת בקשות, אפילו סלסול).
  4. בדוק בקשות POST ו-GET באותו אופן כפי שמתואר בהרצאה.
  5. בדוק בעצמך בקשות PUT ו-DELETE.
חלק 1: מה זה REST חלק 2: תקשורת בין לקוח לשרת
הערות
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION