Spring Boot 跨域與前后端分離
1. 前言
目前,使用 Spring Boot 進(jìn)行前后端分離項(xiàng)目開發(fā),應(yīng)該是主流做法了。這種方式,在開發(fā)、測試階段,都比較方便。
開發(fā)階段,項(xiàng)目組定義好接口規(guī)范后,前端按規(guī)范開發(fā)前端頁面,后端按規(guī)范編寫后端接口,職責(zé)分明。
測試階段,后端是獨(dú)立項(xiàng)目,可以進(jìn)行單元測試。前端可以隨時使用最新版本的后端程序進(jìn)行實(shí)際測試。
前后端分離的模式,有著很多的優(yōu)越性,所以造就了它的流行。
2. 技術(shù)選型
本篇我們通過商品瀏覽項(xiàng)目實(shí)例,展現(xiàn)前后端分離項(xiàng)目的開發(fā)、測試全流程。
技術(shù)選型方面,后端毫無疑問選擇 Spring Boot ,接口風(fēng)格采用 RESTful 標(biāo)準(zhǔn)。前端則使用簡單的 HTML + Bootstrap + jQuery ,并通過 jQuery 的 $.ajax 方法訪問后端接口。
3. 后端開發(fā)流程
3.1 使用 Spring Initializr 構(gòu)建一個 Spring Boot 應(yīng)用
Spring Boot 版本選擇 2.2.5 , Group 為 com.imooc
, Artifact 為 spring-boot-cors
,生成項(xiàng)目后導(dǎo)入 Eclipse 開發(fā)環(huán)境。
3.2 修改 pom.xml
引入 Web 項(xiàng)目依賴,開啟熱部署便于修改測試。
實(shí)例:
<!-- 熱部署 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
<!-- web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
3.3 定義商品類、商品服務(wù)類、商品控制器類
在控制器類中編寫獲取商品列表的接口供前端調(diào)用。
實(shí)例:
/**
* 商品類
*/
public class GoodsDo {
/**
* 商品id
*/
private Long id;
/**
* 商品名稱
*/
private String name;
/**
* 商品價格
*/
private String price;
/**
* 商品圖片
*/
private String pic;
//省略get set
}
實(shí)例:
/**
* 商品服務(wù)類
*/
@Service // 注冊為服務(wù)類
public class GoodsService {
/**
* 獲取商品列表
*/
public List<GoodsDo> getGoodsList() {
List<GoodsDo> goodsList = new ArrayList<GoodsDo>();//模擬從數(shù)據(jù)庫查詢出的結(jié)果返回
GoodsDo goods = new GoodsDo();
goods.setId(1L);
goods.setName("蘋果");
goods.setPic("apple.jpg");
goods.setPrice("3.5");
goodsList.add(goods);
return goodsList;
}
}
實(shí)例:
/**
* 商品控制器類
*/
@RestController
public class GoodsController {
@Autowired
private GoodsService goodsService;
@GetMapping("/goods")//遵循Restful規(guī)范的接口
public List<GoodsDo> getList() {
return goodsService.getGoodsList();
}
}
3.4 啟動應(yīng)用
訪問 http://127.0.0.1:8080/goods
,返回內(nèi)容如下,可見后端接口已經(jīng)可用。
4. 前端開發(fā)流程
前后端分離開發(fā),實(shí)際上前端工作就簡化了。我們直接新建項(xiàng)目文件夾 shop-front (商城前端項(xiàng)目文件夾),然后將前端頁面放到該文件夾即可。
注意該頁面不需要放到 Spring Boot 項(xiàng)目目錄下,隨便找個目錄放置即可。實(shí)際開發(fā)過程中,后端和前端的項(xiàng)目可能都不在一臺計(jì)算機(jī)上。
前端核心業(yè)務(wù)代碼如下,由于前端技術(shù)不是本節(jié)介紹的重點(diǎn),所以不再詳細(xì)解釋,感興趣的同學(xué)可以從 Git倉庫 查看完整代碼 。
實(shí)例:
//初始化方法
$(function () {
var row = "";
$.ajax({
type: "GET",
url: "http://127.0.0.1:8080/goods", //后端接口地址
dataType: "json",
contentType: "application/json; charset=utf-8",
success: function (res) {
$.each(res, function (i, v) {
row = "<tr>";
row += "<td>" + v.id + "</td>";
row += "<td>" + v.name + "</td>";
row += "<td>" + v.price + "</td>";
row += "<td>" + v.pic + "</td>";
row += "</tr>";
$("#goodsTable").append(row);
});
},
error: function (err) {
console.log(err);
}
});
});
開發(fā)完該頁面后,直接使用瀏覽器雙擊打開,查看控制臺發(fā)現(xiàn)有錯誤信息提示。
考驗(yàn)英文水平的時候到了!關(guān)鍵是 has been blocked by CORS policy
,意味著被 CORS 策略阻塞了。我們的前端頁面請求被 CORS 阻塞了,所以沒成功獲取到后端接口返回的數(shù)據(jù)。
5. CORS 跨域介紹
跨域?qū)嶋H上源自瀏覽器的同源策略,所謂同源,指的是協(xié)議、域名、端口都相同的源(域)。瀏覽器會阻止一個域的 JavaScript 腳本向另一個不同的域發(fā)出的請求,這也是為了保護(hù)瀏覽器的安全。
在上面的例子中,發(fā)起請求的網(wǎng)頁與請求資源的 URL 協(xié)議、域名、端口均不同,所以該請求就被瀏覽器阻止了。
CORS 的意思就是跨域資源共享
,是一種允許跨域 HTTP 請求的機(jī)制,在這種情況下我們就要想辦法實(shí)現(xiàn) CORS 跨域了。
6. Spring Boot 跨域的實(shí)現(xiàn)
跨域的方法有很多種,我們此處演示一種常用的跨域方法。我們添加一個配置類,代碼如下:
實(shí)例:
@Configuration//配置類
public class CorsConfig {
@Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurer() {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")//對所有請求路徑
.allowedOrigins("*")//允許所有域名
.allowCredentials(true)//允許cookie等憑證
.allowedMethods("GET", "POST", "DELETE", "PUT","PATCH")//允許所有方法
.maxAge(3600);
}
};
}
}
通過上面的配置類,實(shí)現(xiàn)了允許所有對該 Spring Boot 的請求跨域。
此時再次打開網(wǎng)頁,被跨域策略阻塞的提示消失,界面顯示如下:
7. 小結(jié)
一般在項(xiàng)目開發(fā)過程中,會先根據(jù)功能需求規(guī)劃頁面和后端 API 接口, API 接口往往會形成詳細(xì)的 API 文檔說明。
后端會快速地開發(fā) API 接口,前期并不會將 API 功能完全實(shí)現(xiàn),而是僅僅返回一些測試值。就像本篇文章中后端接口返回的博客列表,并不是真實(shí)從數(shù)據(jù)庫查詢出來的,而是構(gòu)造的測試數(shù)據(jù)。
同期,前端可以根據(jù) API 文檔,編寫前端界面,并調(diào)用后端 API 進(jìn)行測試。
也就是說,前后端實(shí)際上互相不必直接溝通,他們之間的交流是通過 API 文檔完成的。由于后端接口往往采用 RESTful 標(biāo)準(zhǔn)規(guī)范,所以在理解上并不會存在很多問題。
越大型的項(xiàng)目,越需要規(guī)范,越需要職責(zé)分明。 Spring Boot 對后端服務(wù)化的支持實(shí)際上是相當(dāng)?shù)轿坏?,使用幾個簡單的注解,就能輕松構(gòu)建獨(dú)立的后端服務(wù)項(xiàng)目。