นี่คือส่วนสุดท้ายของภาพรวมของ REST ในส่วนก่อนหน้านี้ เราได้กล่าวถึง:
การสร้างโครงการ
ในส่วนนี้ เราจะสร้างแอปพลิเคชัน 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