利用SpringBoot框架如何實(shí)現(xiàn)跨域與自定義查詢功能

利用Spring Boot框架如何實(shí)現(xiàn)跨域與自定義查詢功能?針對(duì)這個(gè)問(wèn)題,這篇文章詳細(xì)介紹了相對(duì)應(yīng)的分析和解答,希望可以幫助更多想解決這個(gè)問(wèn)題的小伙伴找到更簡(jiǎn)單易行的方法。

安源網(wǎng)站建設(shè)公司創(chuàng)新互聯(lián)建站,安源網(wǎng)站設(shè)計(jì)制作,有大型網(wǎng)站制作公司豐富經(jīng)驗(yàn)。已為安源上1000家提供企業(yè)網(wǎng)站建設(shè)服務(wù)。企業(yè)網(wǎng)站搭建\外貿(mào)營(yíng)銷網(wǎng)站建設(shè)要多少錢(qián),請(qǐng)找那個(gè)售后服務(wù)好的安源做網(wǎng)站的公司定做!

跨域請(qǐng)求

定義:當(dāng)我們從本身站點(diǎn)請(qǐng)求不同域名或端口的服務(wù)所提供的資源時(shí),就會(huì)發(fā)起跨域請(qǐng)求。

例如最常見(jiàn)的我們很多的 css 樣式文件是會(huì)鏈接到某個(gè)公共 cdn 服務(wù)器上,而不是在本身的服務(wù)器上,這其實(shí)就是典型的一個(gè)跨域請(qǐng)求。但瀏覽器由于安全原因限制了在腳本( script )中發(fā)起的跨域 HTTP 請(qǐng)求。也就是說(shuō) XMLHttpRequest 和 Fetch 等是遵循“同源規(guī)則”的,即只能訪問(wèn)自己服務(wù)器的指定端口的資源(同一服務(wù)器不同端口也會(huì)視為跨域)。但這種限制在今天,我們的應(yīng)用需要訪問(wèn)多種外部 API 或 資源的時(shí)候就不能滿足開(kāi)發(fā)者的需求了,因此就產(chǎn)生了若干對(duì)于跨域的解決方案,JSONP 是其中一種,但在今天來(lái)看主流的更徹底的解決方案是 CORS ( Cross-Origin Resource Sharing )。

跨域資源共享 ( CORS )

這種機(jī)制將跨域的訪問(wèn)控制權(quán)交給服務(wù)器,這樣可以保證安全的跨域數(shù)據(jù)傳輸?,F(xiàn)代瀏覽器一般會(huì)將 CORS 的支持封裝在 HTTP API 之中( 比如 XMLHttpRequest 和 Fetch ),這樣可以有效控制使用跨域請(qǐng)求的風(fēng)險(xiǎn),因?yàn)槟憷@不過(guò)去,總得要使用 API 吧。

概括來(lái)說(shuō),這個(gè)機(jī)制是增加一系列的 HTTP 頭來(lái)讓服務(wù)器可以描述哪些源是允許使用瀏覽器來(lái)訪問(wèn)資源的。而且對(duì)于簡(jiǎn)單的請(qǐng)求和復(fù)雜請(qǐng)求,處理機(jī)制是不一樣的。

簡(jiǎn)單請(qǐng)求僅允許三個(gè) HTTP 方法:GET,POST 以及 HEAD,另外只能支持若干 header 參數(shù):Accept , Accept-Language , Content-Language , Content-Type (值只能是 application/x-www-form-urlencoded、multipart/form-data 和 text/plain), DPR , Downlink , Save-Data , Viewport-Width 和 Width。

對(duì)于簡(jiǎn)單請(qǐng)求來(lái)說(shuō),比如下面這樣一個(gè)簡(jiǎn)單的GET請(qǐng)求:從 http://me.domain 發(fā)起到 http://another.domain/data/blablabla 的資源請(qǐng)求

GET /data/blablabla/ HTTP/1.1
// 請(qǐng)求的域名
Host: another.domain
...//省略其它部分,重點(diǎn)是下面這句,說(shuō)明了發(fā)起請(qǐng)求者的來(lái)源
Origin: http://me.domain

應(yīng)用了 CORS 的對(duì)方服務(wù)器返回的響應(yīng)應(yīng)該像下面這個(gè)樣子,當(dāng)然這里 Access-Control-Allow-Origin: * 中的 * 表示任何網(wǎng)站都可以訪問(wèn)該資源,如果要限制只能從 me.domain 訪問(wèn),那么需要改成 Access-Control-Allow-Origin: http://me.domain

HTTP/1.1 200 OK
...//省略其它部分
Access-Control-Allow-Origin: *
...//省略其它部分
Content-Type: application/json

那么對(duì)于復(fù)雜請(qǐng)求怎么辦呢?這需要一次預(yù)檢請(qǐng)求和一次實(shí)際的請(qǐng)求,也就是說(shuō)需要兩次和對(duì)方服務(wù)器的請(qǐng)求/響應(yīng)。預(yù)檢請(qǐng)求是以 OPTION 方法進(jìn)行的,因?yàn)?OPTION 方法不會(huì)改變?nèi)魏钨Y源,所以這個(gè)預(yù)檢請(qǐng)求是安全的,它的職責(zé)在于發(fā)送實(shí)際請(qǐng)求將會(huì)使用的 HTTP 方法以及將要發(fā)送的 HEADER 中將攜帶哪些內(nèi)容,這樣對(duì)方服務(wù)器可以根據(jù)預(yù)檢請(qǐng)求的信息決定是否接受。

// 預(yù)檢請(qǐng)求
OPTIONS /resources/post/ HTTP/1.1
Host: another.domain
...// 省略其它部分
Origin: http://me.domain
Access-Control-Request-Method: POST
Access-Control-Request-Headers: Content-Type

服務(wù)器對(duì)預(yù)檢請(qǐng)求的響應(yīng)如下:

HTTP/1.1 200 OK
// 省略其它部分
Access-Control-Allow-Origin: http://me.domain
Access-Control-Allow-Methods: POST, GET, OPTIONS
Access-Control-Allow-Headers: Content-Type
Access-Control-Max-Age: 86400
// 省略其它部分
Content-Type: text/plain

接下來(lái)的正式請(qǐng)求就和上面的簡(jiǎn)單請(qǐng)求差不多了,就不贅述了。

在 Spring Boot 中如何啟用 CORS

啰嗦了這么多,終于進(jìn)入正題,但我一直覺(jué)得不能光知其然而不知其所以然,所以各位就忍了吧。加入 CORS 的支持在 Spring Boot 中簡(jiǎn)單到不忍直視,添加一個(gè)配置類即可:

import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
@Configuration
public class CorsConfig {
 @Bean
 public FilterRegistrationBean corsFilter() {
  UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
  CorsConfiguration config = new CorsConfiguration();
  config.setAllowCredentials(true);
  // 設(shè)置你要允許的網(wǎng)站域名,如果全允許則設(shè)為 *
  config.addAllowedOrigin("http://localhost:4200");
  // 如果要限制 HEADER 或 METHOD 請(qǐng)自行更改
  config.addAllowedHeader("*");
  config.addAllowedMethod("*");
  source.registerCorsConfiguration("/**", config);
  FilterRegistrationBean bean = new FilterRegistrationBean(new CorsFilter(source));
  // 這個(gè)順序很重要哦,為避免麻煩請(qǐng)?jiān)O(shè)置在最前
  bean.setOrder(0);
  return bean;
 }
}

如果我們使用 POSTMAN 訪問(wèn)一下 API,會(huì)發(fā)現(xiàn)得到一個(gè) Invalid CORS request 的響應(yīng),因?yàn)槲覀兊?API 只授權(quán)給了 localhost:4200

利用Spring Boot框架如何實(shí)現(xiàn)跨域與自定義查詢功能

用 POSTMAN 無(wú)法得到請(qǐng)求結(jié)果

當(dāng)然,如果我們使用 CURL 的話是可以訪問(wèn)的,這是因?yàn)?CURL 不是瀏覽器。

嗯嗯,這樣就結(jié)束了,這節(jié)好水,但就是這么簡(jiǎn)單啊。

自定義查詢

我們回過(guò)頭來(lái)再來(lái)看看數(shù)據(jù)查詢,大部分情況下 Spring Data 提供的按方法名進(jìn)行查詢的方式足夠簡(jiǎn)單也足夠強(qiáng)大,但總歸還是有很多局限。為了說(shuō)明這個(gè)問(wèn)題,也順便為我的新 Angular 項(xiàng)目打造一個(gè) API,我們把 API 的需求改一下?,F(xiàn)在我們要做的不是一個(gè)簡(jiǎn)單的 Todo 了,而是類似 Teambition 或 Worktile 那樣的企業(yè)協(xié)作平臺(tái),當(dāng)然我們不會(huì)做的那么復(fù)雜,是個(gè)簡(jiǎn)化版本。那么這時(shí)我們的對(duì)象模型是這樣的:

利用Spring Boot框架如何實(shí)現(xiàn)跨域與自定義查詢功能

主要的領(lǐng)域?qū)ο?/p>

我們首先看一下 Project 這個(gè)對(duì)象,我們來(lái)構(gòu)建它的 API,增刪改沒(méi)啥可講。但是查詢上會(huì)有點(diǎn)不一樣,首先我們并不希望把所有的 Project 都查出來(lái),而是該用戶參與的項(xiàng)目要提供一個(gè) API 給客戶端。

Project 和 User 按關(guān)系型數(shù)據(jù)庫(kù)的看法是個(gè)多對(duì)多的關(guān)系,在MongoDB中這其實(shí)有多種做法,可以在 User 對(duì)象中設(shè)置一個(gè) Project 的集合屬性,也可以在 Project 中設(shè)置 User 的集合屬性 (在我們的例子里是 memebers ),還可以兩者結(jié)合,就是在 User 和 Projet 中互相有對(duì)方的集合屬性。具體采用哪種需要看業(yè)務(wù)場(chǎng)景和性能需求,比如如果任何一個(gè)項(xiàng)目的成員數(shù)如果不會(huì)很大,那么在 Project 中嵌入 User 集合就比較劃算;如果項(xiàng)目的成員較多,但一個(gè)成員歸屬的項(xiàng)目不會(huì)很多的情況下,就可以把 Project 的集合嵌入到 User 中。我們這里采用了第一種做法。

那么接下來(lái)我們來(lái)寫(xiě)該用戶參與的項(xiàng)目的查詢。當(dāng)然我們可以按照 Spring Data 強(qiáng)大的按方法名稱來(lái)生成對(duì)應(yīng)查詢的方式來(lái)做:尋找 members 屬性中包含該用戶的集合

Set<Project> findByMembersContaining(User user)

看起來(lái)還可以,挺簡(jiǎn)單,但是如果我們說(shuō)再加兩個(gè)條件要篩選 project.enabled == true (我們不會(huì)物理刪除項(xiàng)目,而是設(shè)置其標(biāo)志位 enabled,所以這就是篩選未刪除的項(xiàng)目) 和 project.archived == false (項(xiàng)目完結(jié)后需要?dú)w檔,這就是篩選未歸檔的)。這兩個(gè)條件一加上,好家伙,我們的方法名變成了下面這個(gè)樣子,不忍直視?。?/p>

Set<Project> findByMembersContainingAndEnabledAndArchived(User user, boolean enabled, boolean archived)

當(dāng)然好用還是好用了,但是這個(gè)方法名也太長(zhǎng)了,好在 Spring Data 中提供很多種方式自定義查詢,我們介紹一種相對(duì)簡(jiǎn)單的:利用 @Query 注解來(lái)進(jìn)行查詢,方法名字就沒(méi)有那么雷人了:

@Query("{'owner.$id': &#63;#{[0]}, 'enabled': &#63;#{[1]}, 'archived': &#63;#{[2]}}")
Set<Project> findRelated(User user, boolean enabled, boolean archived)

這個(gè)注解中的內(nèi)容是一個(gè) JSON 對(duì)象,就和我們?cè)?MongoDB 的控制臺(tái)查詢的find()中的內(nèi)容是一樣的,只不過(guò)將雙引號(hào)換成單引號(hào),將需要變量用 [0]、[1] 和 [2] 的形式表示第一、第二和第三個(gè)參數(shù)。那么 &#63;#{} 是表示里面的內(nèi)容是個(gè) SpEL ( Spring 的表達(dá)式語(yǔ)言) 表達(dá)式。

所以實(shí)踐中,我們可以在 MongoDB 的控制臺(tái)去實(shí)驗(yàn)語(yǔ)句是否好用,然后在 Spring 中編寫(xiě)表達(dá)式。

db.project.find(
 {
  "owner.$id": ObjectId("58f5a904edc76ab0e033cfc3"),  
  "enabled": true, 
  "archived": false
 })

利用Spring Boot框架如何實(shí)現(xiàn)跨域與自定義查詢功能

在MongoDB的console查詢

數(shù)據(jù)的分頁(yè)

很多時(shí)候我們希望 API 返回的數(shù)據(jù)是可以分頁(yè)的,這個(gè)分頁(yè)問(wèn)題在 Spring Boot 有怎樣便捷的方法呢?我們是否需要再定義一堆什么 pageSize,pageCount,start, off 的參數(shù)呢?答案是完全沒(méi)必要,分頁(yè)這個(gè)事情對(duì)于 Spring Boot 來(lái)說(shuō)很簡(jiǎn)單,只需改變各層級(jí)原有方法中返回的 List 或 Set 對(duì)象為 Page 對(duì)象,傳入?yún)?shù)多一個(gè) Pageable 類型的參數(shù)即可。

// Controller
@RequestMapping(method = RequestMethod.GET)
public Page<Project> findRelated(
  @RequestHeader(value = "userId") String userId,
  @RequestParam(value = "enabled", defaultValue = "true", required = false) boolean enabled,
  @RequestParam(value = "archived", defaultValue = "false", required = false) boolean archived,
  Pageable pageable) {
 return service.findRelated(userId, enabled, archived, pageable);
}
// Repository
@Query("{'owner.$id': &#63;#{[0]}, 'enabled': &#63;#{[1]}, 'archived': &#63;#{[2]}}")
Page<Project> findRelated(ObjectId userId, boolean enabled, boolean archived, Pageable pageable);

現(xiàn)在呢,我們就可以這樣使用了 GET http://localhost:8090/projects/&#63;page=0&size=3 表示取每頁(yè)三個(gè)數(shù)據(jù)取第一頁(yè)。

關(guān)于利用Spring Boot框架如何實(shí)現(xiàn)跨域與自定義查詢功能問(wèn)題的解答就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,如果你還有很多疑惑沒(méi)有解開(kāi),可以關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道了解更多相關(guān)知識(shí)。

標(biāo)題名稱:利用SpringBoot框架如何實(shí)現(xiàn)跨域與自定義查詢功能
當(dāng)前URL:http://www.muchs.cn/article18/gehidp.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供Google、網(wǎng)站制作、服務(wù)器托管、外貿(mào)建站網(wǎng)站收錄、ChatGPT

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)

搜索引擎優(yōu)化