這是 REST 解析的最後一部分。在前面的部分:
創建專案
在本節中,我們將使用 Spring Boot 建立一個小型 RESTful 應用程式。我們的應用程式將在分析最後部分的範例中的客戶端上實現 CRUD(建立、讀取、更新、刪除)操作。首先,我們透過選單File -> New -> Project...建立一個新的 Spring Boot 應用程序 ,在開啟的視窗中,選擇 Spring Initializr 並指定 Project SDK: 點擊 Next 按鈕。在下一個視窗中,指定 Maven 專案類型,指定 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.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>
。卡密鑰將是客戶端 ID,值將是客戶端本身。這樣做是為了不讓範例因使用資料庫的具體細節而超載。但是,將來我們將能夠編寫該介面的另一個實現,其中可以連接真實的資料庫。在套件中,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 將使用依賴注入在需要的地方為我們提供該類別的實例。現在是時候建立控制器了。一個特殊的類,我們在其中實作處理客戶端端點 (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")
- 這裡我們的意思是這個方法處理發送到 /clients 位址的 POST 請求,該方法傳回ResponseEntity<?>
。ResponseEntity
- 用於回傳回應的特殊類別。使用它,我們可以稍後將 HTTP 狀態代碼傳回給客戶端。此方法接受一個參數@RequestBody Client client
,該參數的值是從請求正文中替換的。摘要談到了這一點 @RequestBody
。在方法體內,我們對先前建立的服務呼叫 create 方法,並將其傳遞給參數中接受的客戶端控制器。ResponseEntity
然後我們透過建立一個新物件並將所需的枚舉值傳遞給它來傳回狀態 201 Created 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,除非另有明確指定。這非常適合我們。在該方法內部,使用我們的服務,我們可以獲得所有客戶的清單。接下來,如果清單不是 null 或空,我們將ResponseEntity
使用該類別傳回客戶端列表和 HTTP 狀態 200 OK。否則,我們只會回傳 HTTP 狀態 404 Not Found。接下來,我們將實現透過 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);
}
}
結果,我們的專案結構如下所示:
啟動和測試
main
要運行我們的應用程序,只需運行類別中的方法即可RestExampleApplication
。為了測試 RESTful Web 服務,您需要下載新軟體)事實是,從常規瀏覽器發送 GET 請求非常容易,但對於 POST、PUT 和 DELETE,常規瀏覽器是不夠的。別擔心:您可以使用 Postman 發送任何 HTTP 請求。你可以在這裡下載。下載並安裝後,我們開始測試我們的應用程式。為此,請開啟程式並建立新請求: 點擊左上角的「新建」按鈕。接下來,選擇請求: 下一步,為其命名並儲存。現在讓我們嘗試向伺服器發送 POST 請求並建立第一個客戶端: 我們以這種方式建立多個客戶端。然後我們將請求類型改為GET並發送給伺服器:
一般結果
恭喜:我們已經涵蓋了 REST 主題。所有材料都很龐大,但我們希望它對您有用:-
我們了解了 REST 是什麼。
-
我們熟悉了 REST 的歷史。
-
我們討論了這種架構風格的限制和原則:
- 將架構引入客戶端-伺服器模型;
- 缺乏條件;
- 快取;
- 介面的一致性;
- 層;
- 按需代碼(可選限制)。
-
我們研究了 REST 提供的優勢
-
我們詳細研究了伺服器和客戶端如何使用 HTTP 協定進行互動。
-
讓我們仔細看看請求和回應。他們的組件被拆卸。
-
最後,我們繼續練習,並在 Spring Boot 中編寫了我們自己的小型 RESTful 應用程式。我們甚至學習如何使用 Postman 程式來測試它。
家庭作業
請嘗試以下操作:- 按照上面的描述,創建您自己的 Spring Boot 專案並在其中實現與講座中相同的邏輯。重複一切 1 合 1。
- 啟動它。應用。
- 下載並設定 Postman(或任何其他用於發送請求的工具,甚至是curl)。
- 按照講座中描述的相同方式測試 POST 和 GET 請求。
- 自行測試 PUT 和 DELETE 請求。
GO TO FULL VERSION