นี่คือส่วนสุดท้ายของภาพรวมของ REST ในส่วนก่อนหน้านี้ เราได้กล่าวถึง:
คลิกปุ่ม "ถัดไป" ในหน้าต่างถัดไป ระบุ "Maven Project" เป็นประเภทโครงการ ระบุ "Group" และ "Artifact":
คลิกปุ่ม "Next" ในหน้าต่างถัดไป เราต้องเลือกส่วนประกอบ Spring Framework ที่จำเป็นสำหรับโครงการ Spring Web จะเพียงพอสำหรับเรา:
คลิกปุ่ม "ถัดไป" ตอนนี้สิ่งที่เหลืออยู่คือการระบุชื่อของโครงการและตำแหน่งในระบบไฟล์:
คลิกปุ่ม "เสร็จสิ้น" โครงการถูกสร้างขึ้น และตอนนี้เราสามารถเห็นโครงสร้างของมัน:
IDEA สร้างตัวอธิบายการปรับใช้ Maven (pom.xml) และคลาสหลักของแอปพลิเคชัน (
คลิกปุ่ม "ใหม่" ที่มุมซ้ายบน จากนั้นเลือก "คำขอ":
จากนั้นตั้งชื่อและบันทึก ตอนนี้ลองส่งคำขอ POST ไปยังเซิร์ฟเวอร์และสร้างลูกค้ารายแรก:
เราสร้างลูกค้าจำนวนมากด้วยวิธีนี้ จากนั้นเราเปลี่ยนประเภทคำขอเป็น GET และส่งคำขอไปยังเซิร์ฟเวอร์:
การสร้างโครงการ
ในส่วนนี้ เราจะสร้างแอปพลิเคชัน RESTful ขนาดเล็กโดยใช้ Spring Boot แอปพลิเคชันของเราจะใช้การดำเนินการ CRUD (สร้าง อ่าน อัปเดต ลบ) กับลูกค้าจากตัวอย่างในส่วนก่อนหน้าของภาพรวม ในการเริ่มต้น เราจะสร้างแอปพลิเคชัน Spring Boot ใหม่ผ่านเมนู: ไฟล์ -> ใหม่ -> โครงการ... ในหน้าต่างที่เปิดขึ้น ให้เลือก Spring Initializr และระบุ Project SDK:
คลิกปุ่ม "ถัดไป" ในหน้าต่างถัดไป ระบุ "Maven Project" เป็นประเภทโครงการ ระบุ "Group" และ "Artifact":
คลิกปุ่ม "Next" ในหน้าต่างถัดไป เราต้องเลือกส่วนประกอบ Spring Framework ที่จำเป็นสำหรับโครงการ Spring Web จะเพียงพอสำหรับเรา:
คลิกปุ่ม "ถัดไป" ตอนนี้สิ่งที่เหลืออยู่คือการระบุชื่อของโครงการและตำแหน่งในระบบไฟล์:
คลิกปุ่ม "เสร็จสิ้น" โครงการถูกสร้างขึ้น และตอนนี้เราสามารถเห็นโครงสร้างของมัน:
IDEA สร้างตัวอธิบายการปรับใช้ Maven (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.codegym.lessons/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 (วัตถุ Java เก่าธรรมดา) สร้างmodelแพ็คเกจภายในcom.codegym.lessons.rest_exampleแพ็คเกจ ภายในmodelแพ็คเกจ สร้างCustomer:
public class Customer {
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.codegym.lessons.rest_exampleแพ็คเกจ สร้างserviceแพ็คเกจ และภายในนั้นให้สร้างCustomerServiceส่วนต่อประสาน นี่คือรหัสอินเทอร์เฟซพร้อมความคิดเห็น:
public interface CustomerService {
/**
* Creates a new customer
* @param customer - Customer to be created
*/
void create(Customer customer);
/**
* Returns a list of all existing customers
* @return List of customers
*/
List<Customer> readAll();
/**
* Returns a customer based on its ID
* @param id - Customer ID
* @return - Customer object with the given ID
*/
Customer read(int id);
/**
* Updates the customer with the given ID,
* according to the passed customer
* @param customer - Customer to use to update the data
* @param id - ID of the customer you want to update
* @return - true if the data has been updated, otherwise false
*/
boolean update(Customer customer, int id);
/**
* Deletes the customer with the given ID
* @param id - ID of the customer to be deleted
* @return - true if the customer was deleted, otherwise false
*/
boolean delete(int id);
}
ต่อไป เราต้องใช้อินเทอร์เฟซนี้ ตอนนี้Map<Integer, Customer>จะเก็บลูกค้าของเรา คีย์ของแผนที่จะเป็นรหัสลูกค้า และค่าต่างๆ จะเป็นตัวลูกค้าเอง สิ่งนี้ทำเพื่อไม่ให้โอเวอร์โหลดตัวอย่างนี้ด้วยลักษณะเฉพาะของการทำงานกับฐานข้อมูลจริง อย่างไรก็ตาม ในอนาคตเราจะสามารถเขียนการใช้งานอินเทอร์เฟซอื่นได้ ซึ่งจะทำให้สามารถเชื่อมต่อกับฐานข้อมูลจริงได้ ในserviceแพ็คเกจ สร้างการใช้งานCustomerServiceอินเทอร์เฟซ:
@Service
public class CustomerServiceImpl implements CustomerService {
// Customer repository
private static final Map<Integer, Customer> CUSTOMER_REPOSITORY_MAP = new HashMap<>();
// Variable for generating a customer ID
private static final AtomicInteger CUSTOMER_ID_HOLDER = new AtomicInteger();
@Override
public void create(Customer customer) {
final int customerId = CUSTOMER_ID_HOLDER.incrementAndGet();
customer.setId(customerId);
CUSTOMER_REPOSITORY_MAP.put(customerId, customer);
}
@Override
public List<Customer> readAll() {
return new ArrayList<>(CUSTOMER_REPOSITORY_MAP.values());
}
@Override
public Customer read(int id) {
return CUSTOMER_REPOSITORY_MAP.get(id);
}
@Override
public boolean update(Customer customer, int id) {
if (CUSTOMER_REPOSITORY_MAP.containsKey(id)) {
customer.setId(id);
CUSTOMER_REPOSITORY_MAP.put(id, customer);
return true;
}
return false;
}
@Override
public boolean delete(int id) {
return CUSTOMER_REPOSITORY_MAP.remove(id) != null;
}
}
คำ@Serviceอธิบายประกอบบอกสปริงว่าคลาสนี้เป็นบริการ นี่คือคลาสประเภทพิเศษที่ใช้ตรรกะของแอปพลิเคชันทางธุรกิจบางอย่าง ต่อจากนั้น ด้วยคำอธิบายประกอบนี้ Spring จะใช้การพึ่งพาการฉีดเพื่อให้อินสแตนซ์ของคลาสนี้แก่เราในทุกที่ที่จำเป็น ตอนนี้ได้เวลาสร้างคอนโทรลเลอร์แล้ว นี่คือคลาสพิเศษที่เราจะใช้ตรรกะสำหรับการประมวลผลคำขอของไคลเอ็นต์ที่ส่งไปยังจุดสิ้นสุด (URI) เพื่อให้ชัดเจนยิ่งขึ้น เราจะสร้างคลาสนี้ทีละน้อย ขั้นแรก สร้างคลาสเองและเพิ่มการอ้างอิงในCustomerService:
@RestController
public class CustomerController {
private final CustomerService customerService;
@Autowired
public CustomerController(CustomerService customerService) {
this.customerService = customerService;
}
}
มาอธิบายคำอธิบายประกอบกัน: @RestControllerบอก Spring ว่าคลาสนี้เป็นตัวควบคุม REST กล่าวอีกนัยหนึ่ง คลาสนี้ใช้ตรรกะสำหรับการประมวลผลคำขอของไคลเอ็นต์ @Autowiredบอก Spring ว่าจำเป็นต้องเพิ่มการพึ่งพาที่นี่ เราส่ง ส่วนต่อ CustomerServiceประสานไปยังตัวสร้าง ก่อนหน้านี้ เราทำเครื่องหมายการใช้งานบริการนี้ด้วย@Serviceคำอธิบายประกอบ และตอนนี้ Spring จะสามารถส่งอินสแตนซ์ของการใช้งานนี้ไปยังตัวสร้างของคอนโทรลเลอร์ได้ ต่อไป เราจะใช้วิธีการควบคุมแต่ละวิธีสำหรับการจัดการการทำงานของ CRUD เริ่มต้นด้วยการดำเนินการสร้าง ในการทำเช่นนี้ เราเขียนcreateวิธีการ:
@PostMapping(value = "/customers")
public ResponseEntity<?> create(@RequestBody Customer customer) {
customerService.create(customer);
return new ResponseEntity<>(HttpStatus.CREATED);
}
มาวิเคราะห์วิธีนี้กัน: @PostMapping(value = "/customers")หมายความว่าวิธีนี้จะประมวลผลคำขอ POST ที่ส่งไปยังที่อยู่ "/customers" เมธอดจะคืนค่า a ResponseEntity<?>. A ResponseEntityเป็นคลาสพิเศษสำหรับการตอบกลับ ในภายหลัง เราจะใช้เพื่อส่งคืนรหัสสถานะ HTTP ให้กับลูกค้า วิธีการมี@RequestBody Customer customerพารามิเตอร์ ค่าของพารามิเตอร์นี้มาจากเนื้อหาคำขอ คำ@RequestBodyอธิบายประกอบระบุสิ่งนี้ ภายในเนื้อหาของเมธอด เราเรียกcreate()เมธอดบนบริการที่สร้างไว้ก่อนหน้านี้ และส่งต่อไปยังตัวควบคุมที่ลูกค้าได้รับในพารามิเตอร์ จากนั้นเราจะส่งคืนสถานะ "201 สร้างแล้ว" โดยสร้างResponseEntityวัตถุใหม่และส่งHttpStatusผ่านฟิลด์ enum ที่สอดคล้องกัน ต่อไปเราจะดำเนินการreadการดำเนินการ: ขั้นแรก เราจะดำเนินการเพื่อรับรายชื่อลูกค้าที่มีอยู่ทั้งหมด:
@GetMapping(value = "/customers")
public ResponseEntity<List<Customer>> read() {
final List<Customer> customers = customerService.readAll();
return customers != null && !customers.isEmpty()
? new ResponseEntity<>(customers, HttpStatus.OK)
: new ResponseEntity<>(HttpStatus.NOT_FOUND);
}
มาเริ่มกันเลย: @GetMapping(value = "/customers")— ทุกอย่างที่นี่คล้ายกับ@PostMappingคำอธิบายประกอบ แต่ตอนนี้เรากำลังประมวลผลคำขอ GET ครั้งนี้เราส่งคืน a ResponseEntity<List<Customer>>และนอกเหนือจากสถานะ HTTP แล้ว เราจะส่งคืนเนื้อหาตอบกลับด้วย ซึ่งจะเป็นรายชื่อลูกค้า ในตัวควบคุม REST ของ Spring ทุกอย่างคือออบเจกต์ POJO และคอลเล็กชันของออบเจ็กต์ POJO ซึ่งส่งคืนเป็นเนื้อหาการตอบสนองและจัดลำดับเป็น JSON โดยอัตโนมัติ เว้นแต่จะระบุไว้เป็นอย่างอื่น สิ่งนี้เหมาะกับเราอย่างสมบูรณ์แบบ ภายในวิธีการ เราใช้บริการของเราเพื่อรับรายชื่อลูกค้าทั้งหมด ต่อไป หากรายการไม่เป็นโมฆะและไม่ว่างเปล่า เราจะใช้ResponseEntityคลาสเพื่อส่งคืนรายชื่อลูกค้าและรหัสสถานะ HTTP "200 ตกลง" มิฉะนั้น เราจะส่งคืนรหัสสถานะ HTTP "404 ไม่พบ" ตอนนี้เราจะใช้ความสามารถในการรับลูกค้าโดยใช้ ID ของมัน:
@GetMapping(value = "/customers/{id}")
public ResponseEntity<Customer> read(@PathVariable(name = "id") int id) {
final Customer customer = customerService.read(id);
return customer != null
? new ResponseEntity<>(customer, HttpStatus.OK)
: new ResponseEntity<>(HttpStatus.NOT_FOUND);
}
สิ่งใหม่อย่างหนึ่งที่นี่คือตัวแปรเส้นทาง ตัวแปรถูกกำหนดใน URI value = "/customers/{id}": เราระบุไว้ในวงเล็บปีกกา และเราได้รับเป็นintพารามิเตอร์เมธอดโดยใช้@PathVariable(name = "id")คำอธิบายประกอบ วิธีนี้จะยอมรับคำขอที่ส่งไปยัง URI ในรูปแบบ/customers/{id}ซึ่ง{id}แทนค่าตัวเลขใดๆ ค่านี้จะถูกส่งต่อผ่านint idตัวแปรไปยังพารามิเตอร์เมธอด ในร่างกาย เราได้รับวัตถุCustomerโดยใช้บริการของเราและที่ได้idรับ จากนั้นโดยการเปรียบเทียบกับรายการ เราจะส่งคืนสถานะ "200 ตกลง" และตัวCustomerวัตถุเอง หรือเรียกง่ายๆ ว่าสถานะ "404 ไม่พบ" หากระบบไม่มีลูกค้าidด้วย เรายังต้องใช้การดำเนินการสองอย่าง: อัปเดตและลบ นี่คือรหัสสำหรับวิธีการเหล่านี้:
@PutMapping(value = "/customers/{id}")
public ResponseEntity<?> update(@PathVariable(name = "id") int id, @RequestBody Customer customer) {
final boolean updated = customerService.update(customer, id);
return updated
? new ResponseEntity<>(HttpStatus.OK)
: new ResponseEntity<>(HttpStatus.NOT_MODIFIED);
}
@DeleteMapping(value = "/customers/{id}")
public ResponseEntity<?> delete(@PathVariable(name = "id") int id) {
final boolean deleted = customerService.delete(id);
return deleted
? new ResponseEntity<>(HttpStatus.OK)
: new ResponseEntity<>(HttpStatus.NOT_MODIFIED);
}
วิธีการเหล่านี้ไม่มีอะไรใหม่เป็นหลัก ดังนั้นเราจะข้ามคำอธิบายโดยละเอียดไป สิ่งเดียวที่ควรกล่าวถึงคือupdate()เมธอดจัดการคำขอ PUT ( @PutMappingคำอธิบายประกอบ) และdelete()เมธอดจัดการคำขอ DELETE ( DeleteMappingคำอธิบายประกอบ) นี่คือรหัสเต็มสำหรับคอนโทรลเลอร์:
@RestController
public class CustomerController {
private final CustomerService customerService;
@Autowired
public CustomerController(CustomerService customerService) {
this.customerService = customerService;
}
@PostMapping(value = "/customers")
public ResponseEntity<?> create(@RequestBody Customer customer) {
customerService.create(customer);
return new ResponseEntity<>(HttpStatus.CREATED);
}
@GetMapping(value = "/customers")
public ResponseEntity<List<Customer>> read() {
final List<Customer> customers = customerService.readAll();
return customers != null && !customers.isEmpty()
? new ResponseEntity<>(customers, HttpStatus.OK)
: new ResponseEntity<>(HttpStatus.NOT_FOUND);
}
@GetMapping(value = "/customers/{id}")
public ResponseEntity<Customer> read(@PathVariable(name = "id") int id) {
final Customer customer = customerService.read(id);
return customer != null
? new ResponseEntity<>(customer, HttpStatus.OK)
: new ResponseEntity<>(HttpStatus.NOT_FOUND);
}
@PutMapping(value = "/customers/{id}")
public ResponseEntity<?> update(@PathVariable(name = "id") int id, @RequestBody Customer customer) {
final boolean updated = customerService.update(customer, id);
return updated
? new ResponseEntity<>(HttpStatus.OK)
: new ResponseEntity<>(HttpStatus.NOT_MODIFIED);
}
@DeleteMapping(value = "/customers/{id}")
public ResponseEntity<?> delete(@PathVariable(name = "id") int id) {
final boolean deleted = customerService.delete(id);
return deleted
? new ResponseEntity<>(HttpStatus.OK)
: new ResponseEntity<>(HttpStatus.NOT_MODIFIED);
}
}
เป็นผลให้โครงสร้างของโครงการของเราเป็นดังนี้:
การเปิดตัวและการทดสอบ
ในการเริ่มแอปพลิเคชันของเรา ให้เรียกใช้main()เมธอดในRestExampleApplicationคลาส แต่เพื่อทดสอบบริการเว็บ RESTful เราจำเป็นต้องดาวน์โหลดซอฟต์แวร์เพิ่มเติม ความจริงก็คือคำขอ GET นั้นค่อนข้างง่ายที่จะส่งจากเบราว์เซอร์ทั่วไป แต่เบราว์เซอร์ทั่วไปไม่สามารถส่งคำขอ POST, PUT และ DELETE ได้ ไม่ต้องกังวล คุณสามารถใช้โปรแกรมที่ชื่อว่าบุรุษไปรษณีย์เพื่อส่งคำขอ HTTP คุณสามารถดาวน์โหลดได้ที่นี่ หลังจากดาวน์โหลดและติดตั้ง Postman แล้ว เราจะเริ่มทดสอบแอปพลิเคชันของเรา ในการทำเช่นนี้ ให้เปิดโปรแกรมและสร้างคำขอใหม่:
คลิกปุ่ม "ใหม่" ที่มุมซ้ายบน จากนั้นเลือก "คำขอ":
จากนั้นตั้งชื่อและบันทึก ตอนนี้ลองส่งคำขอ POST ไปยังเซิร์ฟเวอร์และสร้างลูกค้ารายแรก:
เราสร้างลูกค้าจำนวนมากด้วยวิธีนี้ จากนั้นเราเปลี่ยนประเภทคำขอเป็น GET และส่งคำขอไปยังเซิร์ฟเวอร์:
สรุป
ยินดีด้วย! เราได้พักผ่อนเพียงพอแล้ว มีเนื้อหาจำนวนมาก แต่หวังว่าจะเป็นประโยชน์สำหรับคุณ:-
เราได้เรียนรู้ว่า REST คืออะไร
-
เราได้เรียนรู้ว่า REST เกิดขึ้นมาได้อย่างไร
-
เราได้พูดคุยเกี่ยวกับข้อจำกัดและหลักการเบื้องหลังรูปแบบสถาปัตยกรรมนี้:
- สถาปัตยกรรมไคลเอ็นต์เซิร์ฟเวอร์
- ไร้สัญชาติ
- เก็บเอาไว้
- อินเตอร์เฟซที่เหมือนกัน
- ชั้น
- รหัสตามความต้องการ (ไม่บังคับ)
-
เราได้สำรวจประโยชน์ที่ได้รับจาก REST
-
เราได้ตรวจสอบโดยละเอียดว่าเซิร์ฟเวอร์และไคลเอนต์โต้ตอบกันอย่างไรผ่านโปรโตคอล HTTP
-
เราได้ตรวจสอบคำขอและการตอบสนองอย่างใกล้ชิดยิ่งขึ้น เราผ่าส่วนประกอบของมันออก
-
สุดท้าย เราได้รับประสบการณ์จริงจากการเขียนแอปพลิเคชัน RESTful ขนาดเล็กของเราเองโดยใช้ Spring Boot และเรายังได้เรียนรู้วิธีทดสอบโดยใช้บุรุษไปรษณีย์
การบ้าน
ลองดังต่อไปนี้:- ทำตามคำอธิบายด้านบน สร้างโครงการ Spring Boot ของคุณเองและใช้ตรรกะเดียวกับในบทเรียน ทำซ้ำทุกอย่างถูกต้อง
- เปิดแอปพลิเคชัน
- ดาวน์โหลดและกำหนดค่าบุรุษไปรษณีย์ (หรือเครื่องมืออื่นๆ สำหรับส่งคำขอ เช่น curl)
- ทดสอบคำขอ POST และ GET ด้วยวิธีเดียวกับที่อธิบายไว้ในบทเรียน
- ทดสอบคำขอ PUT และ DELETE ด้วยตัวคุณเอง
GO TO FULL VERSION