Spring Boot 開(kāi)發(fā) RESTful 風(fēng)格 Web 項(xiàng)目
1. 前言
很多研發(fā)團(tuán)隊(duì),可能都會(huì)有一個(gè)體會(huì),當(dāng)多人研發(fā)一個(gè)項(xiàng)目時(shí),并不能達(dá)到 1+1>2 的效果。有時(shí)候還會(huì)出現(xiàn) 1+1<1 ,即 2 個(gè)人還不如 1 個(gè)人干得快,甚是悲哀。
就比如我們要開(kāi)發(fā)一個(gè) Web 項(xiàng)目,由前端工程師和后端工程師共同完成。
前端工程師懂 HTML / CSS / JavaScript 和 Bootstrap 等前端技術(shù)與框架,但是幾乎不懂后端 Java 語(yǔ)言。
后端工程師懂 Spring Boot 開(kāi)發(fā),略懂 HTML / CSS / JavaScript ,但是沒(méi)用過(guò)前端框架。
這種情況,如果使用 FreeMarker / Thymeleaf / JSP 等模板引擎,將面臨不小的困難。前端工程師得先去學(xué)習(xí)模板引擎的規(guī)則,后端人員需要跟前端溝通控制器交給模板引擎處理的數(shù)據(jù)。
怎么辦呢,不要擔(dān)心,大佬們?cè)缇徒鉀Q這個(gè)問(wèn)題了。
2. 前后端分離
前后端分離這種概念和技術(shù),早就流行多年了。
具體點(diǎn)說(shuō),前端編寫(xiě) HTML 頁(yè)面,然后通過(guò) Ajax 請(qǐng)求后端接口;后端把接口封裝成 API ,返回 JSON 格式的數(shù)據(jù);前端接收到 JSON 返回?cái)?shù)據(jù)后渲染到頁(yè)面。
前端工程師根本不需要懂后端,調(diào)用后端接口就行。后端使用 Spring Boot 控制器返回 JSON 十分簡(jiǎn)單,給方法添加個(gè)注解,就能將返回值序列化為 JSON 。
前端干前端的活,后端干后端的活,職責(zé)分明,界限明確。這就是前后端分離的好處?。?/p>
3. RESTful 風(fēng)格后端接口
前后端分離時(shí),后端接口可不能太隨意,目前后端接口編寫(xiě)大多遵循 RESTful 風(fēng)格。
做后端接口的公司這么多,如果大家都定義自己的規(guī)范,是不利于公司之間的合作的。如果大家都能遵循一個(gè)規(guī)范來(lái)開(kāi)發(fā)接口,很明顯相關(guān)人員都能省心不少。
RESTful 就是一種非常流行的 HTTP 接口規(guī)范,簡(jiǎn)單明了,使用的人也多,用它準(zhǔn)沒(méi)錯(cuò)。
4. 整體流程說(shuō)明
本節(jié)實(shí)現(xiàn)一個(gè)基于 RESTful 風(fēng)格的 Spring Boot 商品瀏覽 API 實(shí)例。
做事之前,先定整體流程。凡事預(yù)則立,不預(yù)則廢,老祖宗的智慧太厲害了,我們爭(zhēng)取發(fā)揚(yáng)光大。確定流程如下:
5. 開(kāi)發(fā)階段
5.1 根據(jù)需求制定 RESTful 風(fēng)格的接口文檔
既然是要做商品瀏覽頁(yè)面,將商品增刪改查都實(shí)現(xiàn)了就是了。 RESTful 風(fēng)格接口并不麻煩,一般情況下需要項(xiàng)目團(tuán)隊(duì)一起商量制定。此處我們指定如下:
動(dòng)詞 | 接口含義 | 接口地址 |
---|---|---|
GET | 查詢(xún)商品 (id=1) 信息 | http://127.0.0.1:8080/goods/1 |
GET | 查詢(xún)商品列表信息 | http://127.0.0.1:8080/goods |
POST | 新增商品 | http://127.0.0.1:8080/goods |
PUT | 修改商品 (id=1) 信息 | http://127.0.0.1:8080/goods/1 |
DELETE | 刪除商品 (id=1) | http://127.0.0.1:8080/goods/1 |
Tips: RESTful 風(fēng)格通過(guò) HTTP 動(dòng)詞( GET / POST / PUT / DELETE )區(qū)分操作類(lèi)型, URL 格式比較固定,僅此而已,非常簡(jiǎn)單。
5.2 按文檔開(kāi)發(fā)后端 API 接口
相比于使用模板引擎,用 Spring Boot 開(kāi)發(fā)后端接口簡(jiǎn)直太輕松了。通過(guò)給控制器添加注解,就能將控制器方法返回值序列化為 JSON 。程序員最?lèi)?ài),就是輕松又愉快。
5.2.1 使用 Spring Initializr 創(chuàng)建項(xiàng)目
Spring Boot 版本選擇 2.2.5 , Group 為 com.imooc
, Artifact 為 spring-boot-restful
,生成項(xiàng)目后導(dǎo)入 Eclipse 開(kāi)發(fā)環(huán)境。
像這種老套的重復(fù)操作,我還是拿出來(lái)講講,為何,因?yàn)橐^續(xù)呵護(hù)我們的初學(xué)者們。萬(wàn)一有朋友因?yàn)橐粋€(gè)小地方看不明白,喪失了學(xué)習(xí)編程的動(dòng)力,那就是罪過(guò)了。
5.2.2 引入項(xiàng)目依賴(lài)
RESTful 項(xiàng)目其實(shí)就是標(biāo)準(zhǔn)的 Web 項(xiàng)目,引入 Web 項(xiàng)目依賴(lài)即可。
實(shí)例:
<!-- 引入web項(xiàng)目相關(guān)依賴(lài) -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
5.2.3 創(chuàng)建商品類(lèi)與商品服務(wù)類(lèi)
創(chuàng)建商品類(lèi)與商品服務(wù)類(lèi),以完成對(duì)商品的增刪改查操作。由于本章我們的重點(diǎn)是演示 RESTful 后端接口,所以此處沒(méi)有操作真實(shí)的數(shù)據(jù)庫(kù)。
實(shí)例:
/**
* 商品類(lèi)
*/
public class GoodsDo {
/**
* 商品id
*/
private Long id;
/**
* 商品名稱(chēng)
*/
private String name;
/**
* 商品價(jià)格
*/
private String price;
/**
* 商品圖片
*/
private String pic;
//省略get set方法
}
實(shí)例:
/**
* 商品服務(wù)
*/
@Service // 注冊(cè)為服務(wù)類(lèi)
public class GoodsService {
/**
* 獲取商品列表
*/
public List<GoodsDo> getGoodsList() {
List<GoodsDo> goodsList = new ArrayList<GoodsDo>();
GoodsDo goods = new GoodsDo();
goods.setId(1L);
goods.setName("蘋(píng)果");
goods.setPic("apple.jpg");
goods.setPrice("3.5");
goodsList.add(goods);
return goodsList;
}
/**
* 按id獲取商品信息,模擬返回對(duì)應(yīng)商品信息
*/
public GoodsDo getGoodsById(Long id) {
GoodsDo goods = new GoodsDo();
goods.setId(1L);
goods.setName("蘋(píng)果");
goods.setPic("apple.jpg");
goods.setPrice("3.5");
return goods;
}
/**
* 新增商品,模擬返回?cái)?shù)據(jù)庫(kù)影響行數(shù)
*/
public int addGoods(GoodsDo goods) {
return 1;
}
/**
* 根據(jù)商品id更新商品信息,模擬返回?cái)?shù)據(jù)庫(kù)影響行數(shù)
*/
public int editGoods(GoodsDo goods) {
return 1;
}
/**
* 根據(jù)商品id刪除對(duì)應(yīng)商品,模擬返回?cái)?shù)據(jù)庫(kù)影響行數(shù)
*/
public int removeGoods(Long id) {
return 1;
}
}
Tips: 服務(wù)層方法,建議不要使用 select /insert/update /delete 命名,因?yàn)榉?wù)層處理的邏輯往往不止于關(guān)系數(shù)據(jù)庫(kù)表的增刪改查。此處采用的是 get /add/edit /remove 。
5.2.4 根據(jù) API 文檔實(shí)現(xiàn)控制器方法
此處需要解釋的地方我都寫(xiě)在注釋中了。
實(shí)例:
@RestController // 通過(guò)該注解,第一是將GoodsController注冊(cè)為控制器,可以響應(yīng)Http請(qǐng)求;第二是可以將控制器中的方法返回值序列化為json格式。
public class GoodsController {
@Autowired // 自動(dòng)裝配goodsService
private GoodsService goodsService;
/**
* 查詢(xún)商品信息
* 1、@GetMapping表示可以使用get方法請(qǐng)求該api
* 2、"/goods/{id}"表示請(qǐng)求路徑為/goods/{id}的形式,其中{id}為占位符
* 3、@PathVariable("id")表示將占位符{id}的值傳遞給id
* 4、也就是說(shuō)/goods/123請(qǐng)求的話(huà),會(huì)將123傳遞給參數(shù)id
*/
@GetMapping("/goods/{id}")
public GoodsDo getOne(@PathVariable("id") long id) {
return goodsService.getGoodsById(id);
}
/**
* 查詢(xún)商品列表,使用get方法
*/
@GetMapping("/goods")
public List<GoodsDo> getList() {
return goodsService.getGoodsList();
}
/**
* 新增商品
* 1、@PostMapping表示使用post方法
* 2、@RequestBody表示將請(qǐng)求中的json信息轉(zhuǎn)換為GoodsDo類(lèi)型的對(duì)象信息,該轉(zhuǎn)換也是由SpringMVC自動(dòng)完成的
*/
@PostMapping("/goods")
public void add(@RequestBody GoodsDo goods) {
goodsService.addGoods(goods);
}
/**
* 修改商品
*/
@PutMapping("/goods/{id}")
public void update(@PathVariable("id") long id, @RequestBody GoodsDo goods) {
// 修改指定id的商品信息
goods.setId(id);
goodsService.editGoods(goods);
}
/**
* 刪除商品
*/
@DeleteMapping("/goods/{id}")
public void delete(@PathVariable("id") long id) {
goodsService.removeGoods(id);
}
}
5.3 使用 Postman 測(cè)試 API 接口可用
后端開(kāi)發(fā)完 API 接口后,需要先進(jìn)行下簡(jiǎn)單測(cè)試以保證接口是正確可用的。
我們可以使用 Postman 進(jìn)行簡(jiǎn)單測(cè)試。啟動(dòng) Spring Boot 項(xiàng)目后,使用 Postman 進(jìn)行可視化測(cè)試,此處結(jié)果如下:
6. 視頻演示
7. 小結(jié)
使用 Spring Boot 開(kāi)發(fā) RESTful 風(fēng)格的 Web 項(xiàng)目,是當(dāng)前主流的 Web 項(xiàng)目開(kāi)發(fā)模式。
這種開(kāi)發(fā)模式的特點(diǎn)就是簡(jiǎn)單、明確。簡(jiǎn)單主要是依賴(lài) Spring Boot 實(shí)現(xiàn),明確就是靠 RESTful 風(fēng)格來(lái)規(guī)范。
簡(jiǎn)單的目的就是提高開(kāi)發(fā)效率;明確的目的是統(tǒng)一規(guī)范,從而降低溝通成本,最終也是為了提高開(kāi)發(fā)效率。
Spring Boot 和 RESTful ,絕配!