JavaRush /จาวาบล็อก /Random-TH /ภาพรวมของ REST ส่วนที่ 3: การสร้างบริการ RESTful ใน Sprin...

ภาพรวมของ REST ส่วนที่ 3: การสร้างบริการ RESTful ใน Spring Boot

เผยแพร่ในกลุ่ม
นี่เป็นส่วนสุดท้ายของการแยกวิเคราะห์ REST ในส่วนก่อนหน้า: ภาพรวมของ REST  ส่วนที่ 3: การสร้างบริการ RESTful ใน Spring Boot - 1

การสร้างโครงการ

ในส่วนนี้ เราจะสร้างแอปพลิเคชัน RESTful ขนาดเล็กโดยใช้ Spring Boot แอปพลิเคชันของเราจะใช้การดำเนินการ CRUD (สร้าง อ่าน อัปเดต ลบ) กับไคลเอนต์จากตัวอย่างจากส่วนสุดท้ายของการวิเคราะห์ ขั้นแรก เรามาสร้างแอปพลิเคชัน Spring Boot ใหม่ผ่านเมนูFile -> New -> Project... ในหน้าต่างที่เปิดขึ้น ให้เลือก Spring Initializr แล้วระบุ Project SDK: ภาพรวมของ REST  ส่วนที่ 3: การสร้างบริการ RESTful ใน Spring Boot - 2คลิกปุ่ม Next ในหน้าต่างถัดไป ให้ระบุประเภทโปรเจ็กต์ Maven ระบุกลุ่มและสิ่งประดิษฐ์: ภาพรวมของ REST  ส่วนที่ 3: การสร้างบริการ RESTful ใน Spring Boot - 3คลิกปุ่มถัดไป ในหน้าต่างถัดไป เราต้องเลือกส่วนประกอบ Spring Framework ที่จำเป็นสำหรับโครงการ Spring Web จะเพียงพอสำหรับเรา: ภาพรวมของ REST  ส่วนที่ 3: การสร้างบริการ RESTful ใน Spring Boot - 4คลิกปุ่มถัดไป ถัดไป สิ่งที่เหลืออยู่คือการระบุชื่อของโครงการและตำแหน่งในระบบไฟล์: ภาพรวมของ REST  ส่วนที่ 3: การสร้างบริการ RESTful ใน Spring Boot - 5คลิกปุ่มเสร็จสิ้น โครงการได้ถูกสร้างขึ้นแล้ว ตอนนี้เราสามารถเห็นโครงสร้างของมันได้แล้ว: ภาพรวมของ REST  ส่วนที่ 3: การสร้างบริการ RESTful ใน Spring Boot - 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>
ส่วนที่เหลือตัวอย่างการใช้งาน:
@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 ว่าคลาสนี้เป็นบริการ นี่คือคลาสชนิดพิเศษที่ใช้ตรรกะทางธุรกิจบางอย่างของแอปพลิเคชัน ต่อจากนั้น ต้องขอบคุณคำอธิบายประกอบนี้ 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และส่งค่าแจงนับที่ต้องการไป 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 OK โดยใช้คลาส มิฉะนั้น เราจะส่งคืนสถานะ HTTP 404 ไม่พบ ต่อไป เราจะใช้ความสามารถในการรับลูกค้าด้วย 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);
}
สิ่งใหม่ก็คือตอนนี้เรามีตัวแปรเส้นทางแล้ว ตัวแปรที่กำหนดไว้ใน URI value = "/clients/{id}". เราระบุไว้ในวงเล็บปีกกา และในพารามิเตอร์ของเมธอด เรายอมรับว่ามันเป็นintตัวแปรโดยใช้คำอธิบาย@PathVariable(name = "id")ประกอบ วิธีนี้จะยอมรับคำขอ uri ของแบบฟอร์ม/clients/{id}โดยที่{id}อาจมีค่าตัวเลข แทนได้ ค่านี้จะถูกส่งต่อไปยังตัวแปรint id— พารามิเตอร์เมธอด ในร่างกายเราได้รับวัตถุClientโดยใช้บริการของเราและidยอมรับ จากนั้น โดยการเปรียบเทียบกับรายการ เราจะส่งคืนสถานะ 200 OK และอ็อบเจ็กต์นั้นเองClientหรือเพียงสถานะ 404 Not Found หาก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: การสร้างบริการ RESTful ใน Spring Boot - 7

เปิดตัวและทดสอบ

ในการรันแอปพลิเคชัน ของเรา เพียงแค่รันเมธอดmainในคลาส RestExampleApplicationและเพื่อทดสอบบริการเว็บ RESTful คุณต้องดาวน์โหลดซอฟต์แวร์ใหม่) ความจริงก็คือคำขอ GET นั้นค่อนข้างง่ายในการส่งจากเบราว์เซอร์ทั่วไป แต่สำหรับ POST, PUT และ DELETE เบราว์เซอร์ทั่วไปยังไม่เพียงพอ ไม่ต้องกังวล คุณสามารถใช้บุรุษไปรษณีย์เพื่อส่งคำขอ HTTP ใดๆ ได้ คุณสามารถดาวน์โหลดได้จากที่นี่ หลังจากดาวน์โหลดและติดตั้งแล้ว เราจะเริ่มทดสอบแอปพลิเคชันของเรา ในการดำเนินการนี้ ให้เปิดโปรแกรมและสร้างคำขอใหม่: ภาพรวมของ REST  ส่วนที่ 3: การสร้างบริการ RESTful ใน Spring Boot - 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 และเรายังได้เรียนรู้วิธีทดสอบโดยใช้โปรแกรมบุรุษไปรษณีย์อีกด้วย

วุ้ย. มันกลายเป็นเรื่องใหญ่โต แต่ก็มีบางอย่างที่ต้องทำเป็นการบ้าน

การบ้าน

ลองดังต่อไปนี้:
  1. ตามคำอธิบายข้างต้น สร้างโปรเจ็กต์ Spring Boot ของคุณเอง และใช้ตรรกะเดียวกันกับในการบรรยาย ทำซ้ำทุกอย่าง 1 ใน 1
  2. เปิดตัวมัน แอปพลิเคชัน.
  3. ดาวน์โหลดและตั้งค่าบุรุษไปรษณีย์ (หรือเครื่องมืออื่น ๆ สำหรับการส่งคำขอ แม้กระทั่งขด)
  4. ทดสอบคำขอ POST และ GET ในลักษณะเดียวกับที่อธิบายในการบรรยาย
  5. ทดสอบคำขอ PUT และ DELETE ด้วยตัวคุณเอง
ส่วนที่ 1: REST คืออะไร ส่วนที่ 2: การสื่อสารระหว่างไคลเอนต์และเซิร์ฟเวอร์
ความคิดเห็น
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION