SpringBoot 對Restful的支援
一、RESTful風格API的好處
-
RESTful是基於http方法的API設計風格,而不是一種新的技術. url和http的method和statuscode都是很有歷史的技術。
-
看Url就知道要什麼資源
-
看http method就知道針對資源幹什麼
-
看http status code就知道結果如何
規範了程式設計師的程式碼開發,為前端後端互動減少了介面交流的口舌成本,是"約定大於配置"的體現。通過下面的設計,大家來理解一下這三句話。
二、RESTful風格API的設計風格
-
REST 是面向資源的(名詞)
REST 通過 URI 暴露資源時,會強調不要在 URI 中出現動詞。比如:
不符合REST的介面URI | 符合REST介面URI | 功能 |
---|---|---|
GET /api/getDogs | GET /api/dogs/{id} | 獲取一個小狗狗 |
GET /api/getDogs | GET /api/dogs | 獲取所有小狗狗 |
GET /api/addDogs | POST /api/dogs | 新增一個小狗狗 |
GET /api/editDogs/{id} | PUT /api/dogs/{id} | 修改一個小狗狗 |
GET /api/deleteDogs/{id} | DELETE /api/dogs/{id} | 刪除一個小狗狗 |
-
用HTTP方法體現對資源的操作(動詞)
- GET : 獲取資源
- POST : 新增資源
- PUT : 修改資源
- DELETE : 刪除資源
實際上,這四個動詞實際上就對應著增刪改查四個操作,這就利用了HTTP動詞來表示對資源的操作
-
HTTP狀態碼
通過HTTP狀態碼體現動作的結果,不要自定義
200 OK
400 Bad Request
500 Internal Server Error
在 APP 與 API 的互動當中,其結果逃不出這三種狀態:
- 所有事情都按預期正確執行完畢 - 成功
- APP 發生了一些錯誤 – 客戶端錯誤(如:校驗使用者輸入身份證,結果輸入的是軍官證,就是客戶端錯誤)
- API 發生了一些錯誤 – 伺服器端錯誤(各種編碼bug或服務內部自己導致的異常)
這三種狀態與上面的狀態碼是一一對應的。如果你覺得這三種狀態,分類處理結果太寬泛,http-statuscode還有很多。建議還是要遵循KISS(Keep It Stupid and Simple)原則,上面的三種狀態碼完全可以覆蓋99%以上的場景。三個狀態碼大家都記得住,多了就不一定了。
-
Get方法和查詢引數不應該改變資料
改變資料的事交給POST、PUT、DELETE
-
使用複數名詞
/dogs 而不是 /dog
-
複雜資源關係的表達
GET /cars/711/drivers/ 返回 使用car 711的所有司機
GET /cars/711/drivers/4 返回 使用car 711的4號司機
-
高階用法:HATEOAS
Hypermedia as the Engine of Application State 超媒體作為應用狀態的引擎 RESTful API最好做到Hypermedia,或HATEOAS,即返回結果中提供連結,連向其他API方法,使得使用者不查文件,也知道下一步應該做什麼。比如,當用戶向api.example.com的根目錄發出請求,會得到這樣一個文件。
{"link": {
"rel": "collection https://www.example.com/zoos",
"href": "https://api.example.com/zoos",
"title": "List of zoos",
"type": "application/vnd.yourformat+json"
}}
上面程式碼表示,文件中有一個link屬性,使用者讀取這個屬性就知道下一步該呼叫什麼API了。
-
為集合提供過濾 排序 選擇和分頁等功能
- Filtering過濾:
使用唯一的查詢引數進行過濾:
GET /cars?color=red 返回紅色的cars
GET /cars?seats<=2 返回小於兩座位的cars集合
- Sorting排序:
允許針對多個欄位排序
GET /cars?sort=-manufactorer,+model
這是返回根據生產者降序和模型升序排列的car集合
- Field selection
移動端能夠顯示其中一些欄位,它們其實不需要一個資源的所有欄位,給API消費者一個選擇欄位的能力,
這會降低網路流量,提高API可用性。
GET /cars?fields=manufacturer,model,id,color
- Paging分頁
使用 limit 和offset.實現分頁,預設limit=20 和offset=0;
GET /cars?offset=10&limit=5
-
版本化你的API
使得API版本變得強制性,不要釋出無版本的API。
/api/v1/blog
面向擴充套件開放,面向修改關閉。
三、開發REST介面
-
第一步:定義資源(物件)
@Data
@Builder
public class Article {
private Long id;
private String author;
private String title;
private String content;
private Date createTime;
}
- @Data註解幫我們定義了一系列常用方法,如:getters、setters、hashcode、equals等
-
第二步:HTTP方法與Controller(動作)
@Slf4j
@RestController
@RequestMapping("/rest")
public class ArticleRestController {
@RequestMapping(value = "/article", method = POST, produces = "application/json")
public AjaxResponse saveArticle(@RequestBody Article article) {
log.info("saveArticle:{}",article);
return AjaxResponse.success(article);
}
@RequestMapping(value = "/article/{id}", method = DELETE, produces = "application/json")
public AjaxResponse deleteArticle(@PathVariable Long id) {
log.info("deleteArticle:{}",id);
return AjaxResponse.success(id);
}
@RequestMapping(value = "/article/{id}", method = PUT, produces = "application/json")
public AjaxResponse updateArticle(@PathVariable Long id, @RequestBody Article article) {
article.setId(id);
log.info("updateArticle:{}",article);
return AjaxResponse.success(article);
}
@RequestMapping(value = "/article/{id}", method = GET, produces = "application/json")
public AjaxResponse getArticle(@PathVariable Long id) {
Article article1 = Article.builder().id(1L).author("zimug").content("spring boot 2.深入淺出").createTime(new Date()).title("t1").build();
return AjaxResponse.success(article1);
}
}
- 加上@Slf4j註解,就可以直接使用log變數列印日誌
下面這個類是用於統一資料響應介面標準的。它的作用是:統一所有開發人員響應前端請求的返回結果格式,減少前後端開發人員溝通成本,是開發約定的落地。在異常處理的章節會做更加詳細的說明。
public class AjaxResponse {
private boolean isok; //請求是否處理成功
private int code; //請求響應狀態碼(200、400、500)
private String message; //請求結果描述資訊
private Object data; //請求結果資料
private AjaxResponse() {
}
public static AjaxResponse success() {
AjaxResponse resultBean = new AjaxResponse();
resultBean.setIsok(true);
resultBean.setCode(200);
resultBean.setMessage("success");
return resultBean;
}
public static AjaxResponse success(Object data) {
AjaxResponse resultBean = new AjaxResponse();
resultBean.setIsok(true);
resultBean.setCode(200);
resultBean.setMessage("success");
resultBean.setData(data);
return resultBean;
}
// getter / setter 略
}
四、REST介面開發常用的註解
-
@RestController與@Controller
@RestController相當於 @Controller和@ResponseBody結合。它有兩層含義:一是作為控制器注入到Spring上下文環境,二是請求響應為資料序列化(預設序列化方式是JSON),而不是跳轉到html或模板頁面。
-
@RequestMapping 與@GetMapping、@PutMapping、@PostMapping、@DeleteMapping
@RequestMapping(value = “/article”, method = RequestMethod.GET) 新方法可以簡寫為: @GetMapping("/article"),其他同理。
-
@RequestBody與@ResponseBody
用於接收和響應序列化資料(JSON),可以支援巢狀JSON資料結構。
-
@PathVariable 與@RequestParam
PathVariable用於URI上的{引數}
RequestParam用於接收普通方式提交