Java開發(fā)學(xué)習(xí)----SpringMVC之Rest風(fēng)格解析及快速開發(fā)

一暇韧、REST簡介

REST?(Representational State Transfer)叶摄,表現(xiàn)形式狀態(tài)轉(zhuǎn)換,它是一種軟件架構(gòu)?風(fēng)格

當(dāng)我們想表示一個網(wǎng)絡(luò)資源的時候趟佃,可以使用兩種方式:

傳統(tǒng)風(fēng)格資源描述形式

http://localhost/user/getById?id=1?查詢id為1的用戶信息

http://localhost/user/saveUser?保存用戶信息

REST風(fēng)格描述形式

http://localhost/user/1

http://localhost/user

傳統(tǒng)方式一般是一個請求url對應(yīng)一種操作客税,這樣做不僅麻煩惨恭,也不安全,因為會程序的人讀取了你的請求url地址弹惦,就大概知道該url實現(xiàn)的是一個什么樣的操作否淤。

查看REST風(fēng)格的描述悄但,你會發(fā)現(xiàn)請求地址變的簡單了棠隐,并且光看請求URL并不是很能猜出來該URL的具體功能

所以REST的優(yōu)點有:

隱藏資源的訪問行為,無法通過地址得知對資源是何種操作

書寫簡化

但是我們的問題也隨之而來了檐嚣,一個相同的url地址即可以是新增也可以是修改或者查詢助泽,那么到底我們該如何區(qū)分該請求到底是什么操作呢?

按照REST風(fēng)格訪問資源時使用?行為動作?區(qū)分對資源進(jìn)行了何種操作

http://localhost/users?查詢?nèi)坑脩粜畔?采用GET請求(查詢)

http://localhost/users/1?查詢指定用戶信息 采用GET請求(查詢)

http://localhost/users?添加用戶信息 采用POST請求(新增/保存)

http://localhost/users?修改用戶信息 采用PUT請求(修改/更新)

http://localhost/users/1?刪除用戶信息 采用DELETE請求(刪除)

請求的方式比較多,但是比較常用的就4種嚎京,分別是?GET?,?POST?,?PUT?,?DELETE?嗡贺。

按照不同的請求方式代表不同的操作類型。

發(fā)送GET請求是用來做查詢

發(fā)送POST請求是用來做新增

發(fā)送PUT請求是用來做修改

發(fā)送DELETE請求是用來做刪除

注意:

上述行為是約定方式鞍帝,約定不是規(guī)范诫睬,可以打破,所以稱REST風(fēng)格帕涌,而不是REST規(guī)范

REST提供了對應(yīng)的架構(gòu)方式摄凡,按照這種架構(gòu)設(shè)計項目可以降低開發(fā)的復(fù)雜性续徽,提高系統(tǒng)的可伸縮性

REST中規(guī)定GET/POST/PUT/DELETE針對的是查詢/新增/修改/刪除,但是我們?nèi)绻且肎ET請求做刪除亲澡,這點在程序上運行是可以實現(xiàn)的

描述模塊的名稱通常使用復(fù)數(shù)钦扭,也就是加s的格式描述,表示此類資源床绪,而非單個資源客情,例如:users、books癞己、accounts......

清楚了什么是REST風(fēng)格后膀斋,我們后期會經(jīng)常提到一個概念叫?RESTful?,那什么又是RESTful呢?

根據(jù)REST風(fēng)格對資源進(jìn)行訪問稱為?RESTful?痹雅。

后期我們在進(jìn)行開發(fā)的過程中概页,大多是都是遵從REST風(fēng)格來訪問我們的后臺服務(wù),所以可以說咱們以后都是基于RESTful來進(jìn)行開發(fā)的练慕。

二惰匙、RESTful入門案例

2.1 環(huán)境準(zhǔn)備

創(chuàng)建一個Web的Maven項目

參考?Java開發(fā)學(xué)習(xí)(二十三)----SpringMVC入門案例、工作流程解析及設(shè)置bean加載控制?中環(huán)境準(zhǔn)備

pom.xml添加Spring依賴

<?xml version="1.0"encoding="UTF-8"?>4.0.0com.itheimaspringmvc_06_rest1.0-SNAPSHOTwarjavax.servletjavax.servlet-api3.1.0providedorg.springframeworkspring-webmvc5.2.10.RELEASEcom.fasterxml.jackson.corejackson-databind2.9.0org.apache.tomcat.maventomcat7-maven-plugin2.180/

創(chuàng)建對應(yīng)的配置類

publicclassServletContainersInitConfigextendsAbstractAnnotationConfigDispatcherServletInitializer{protectedClass[] getRootConfigClasses() {returnnewClass[0];? ? }protectedClass[] getServletConfigClasses() {returnnewClass[]{SpringMvcConfig.class};? ? }protectedString[] getServletMappings() {returnnewString[]{"/"};? ? }//亂碼處理@OverrideprotectedFilter[] getServletFilters() {CharacterEncodingFilterfilter =newCharacterEncodingFilter();? ? ? ? filter.setEncoding("UTF-8");returnnewFilter[]{filter};? ? }}@Configuration@ComponentScan("com.itheima.controller")//開啟json數(shù)據(jù)類型自動轉(zhuǎn)換@EnableWebMvcpublicclassSpringMvcConfig{}

編寫模型類User和Book

publicclassUser{privateString name;privateintage;//getter...setter...toString省略}publicclassBook{privateString name;privatedoubleprice;//getter...setter...toString省略}

編寫UserController和BookController

@ControllerpublicclassUserController{@RequestMapping("/save")@ResponseBodypublicString save(@RequestBodyUser user) {? ? ? ? System.out.println("user save..."+user);return"{'module':'user save'}";? ? }@RequestMapping("/delete")@ResponseBodypublicString delete(Integer id) {? ? ? ? System.out.println("user delete..."+ id);return"{'module':'user delete'}";? ? }@RequestMapping("/update")@ResponseBodypublicString update(@RequestBodyUser user) {? ? ? ? System.out.println("user update..."+ user);return"{'module':'user update'}";? ? }@RequestMapping("/getById")@ResponseBodypublicString getById(Integer id) {? ? ? ? System.out.println("user getById..."+ id);return"{'module':'user getById'}";? ? }@RequestMapping("/findAll")@ResponseBodypublicString getAll() {? ? ? ? System.out.println("user getAll...");return"{'module':'user getAll'}";? ? }}@ControllerpublicclassBookController{@RequestMapping(value ="/books",method = RequestMethod.POST)@ResponseBodypublicString save(@RequestBodyBook book){? ? ? ? System.out.println("book save..."+ book);return"{'module':'book save'}";? ? }@RequestMapping(value ="/books/{id}",method = RequestMethod.DELETE)@ResponseBodypublicString delete(@PathVariableInteger id){? ? ? ? System.out.println("book delete..."+ id);return"{'module':'book delete'}";? ? }@RequestMapping(value ="/books",method = RequestMethod.PUT)@ResponseBodypublicString update(@RequestBodyBook book){? ? ? ? System.out.println("book update..."+ book);return"{'module':'book update'}";? ? }@RequestMapping(value ="/books/{id}",method = RequestMethod.GET)@ResponseBodypublicString getById(@PathVariableInteger id){? ? ? ? System.out.println("book getById..."+ id);return"{'module':'book getById'}";? ? }@RequestMapping(value ="/books",method = RequestMethod.GET)@ResponseBodypublicString getAll(){? ? ? ? System.out.println("book getAll...");return"{'module':'book getAll'}";? ? }? ? }

最終創(chuàng)建好的項目結(jié)構(gòu)如下:

2.2 思路分析

需求:將增刪改查替換成RESTful的開發(fā)方式铃将。

1.不同的請求有不同的路徑,現(xiàn)在要將其修改為統(tǒng)一的請求路徑

修改前: 新增: /save ,修改: /update,刪除 /delete...

修改后: 增刪改查: /users

2.根據(jù)GET查詢项鬼、POST新增、PUT修改劲阎、DELETE刪除對方法的請求方式進(jìn)行限定

3.發(fā)送請求的過程中如何設(shè)置請求參數(shù)?

2.3 修改成為RESTful風(fēng)格

新增

@ControllerpublicclassUserController{//設(shè)置當(dāng)前請求方法為POST绘盟,表示REST風(fēng)格中的添加操作@RequestMapping(value ="/users",method = RequestMethod.POST)@ResponseBodypublicString save() {? ? ? ? System.out.println("user save...");return"{'module':'user save'}";? ? }}

將請求路徑更改為?/users

訪問該方法使用 POST:?http://localhost/users

使用method屬性限定該方法的訪問方式為?POST

如果發(fā)送的不是POST請求,比如發(fā)送GET請求悯仙,則會報錯

刪除

@ControllerpublicclassUserController{//設(shè)置當(dāng)前請求方法為DELETE龄毡,表示REST風(fēng)格中的刪除操作@RequestMapping(value ="/users",method = RequestMethod.DELETE)@ResponseBodypublicString delete(Integer id) {? ? ? ? System.out.println("user delete..."+ id);return"{'module':'user delete'}";? ? }}

將請求路徑更改為?/users

訪問該方法使用 DELETE:?http://localhost/users

訪問成功,但是刪除方法沒有攜帶所要刪除數(shù)據(jù)的id,所以針對RESTful的開發(fā)锡垄,如何攜帶數(shù)據(jù)參數(shù)?

傳遞路徑參數(shù)

前端發(fā)送請求的時候使用:?http://localhost/users/1?,路徑中的?1?就是我們想要傳遞的參數(shù)沦零。

后端獲取參數(shù),需要做如下修改:

修改@RequestMapping的value屬性货岭,將其中修改為?/users/{id}?路操,目的是和路徑匹配

在方法的形參前添加@PathVariable注解

@ControllerpublicclassUserController{//設(shè)置當(dāng)前請求方法為DELETE,表示REST風(fēng)格中的刪除操作@RequestMapping(value ="/users/{id}",method = RequestMethod.DELETE)@ResponseBodypublicString delete(@PathVariableInteger id) {? ? ? ? System.out.println("user delete..."+ id);return"{'module':'user delete'}";? ? }}

思考如下兩個問題:

(1)如果方法形參的名稱和路徑?{}?中的值不一致千贯,該怎么辦?

(2)如果有多個參數(shù)需要傳遞該如何編寫?

前端發(fā)送請求的時候使用:?http://localhost/users/1/tom?,路徑中的?1?和?tom?就是我們想要傳遞的兩個參數(shù)屯仗。

后端獲取參數(shù),需要做如下修改:

@ControllerpublicclassUserController{//設(shè)置當(dāng)前請求方法為DELETE搔谴,表示REST風(fēng)格中的刪除操作@RequestMapping(value ="/users/{id}/{name}",method = RequestMethod.DELETE)@ResponseBodypublicString delete(@PathVariableInteger id,@PathVariableString name) {? ? ? ? System.out.println("user delete..."+ id+","+name);return"{'module':'user delete'}";? ? }}

修改

@ControllerpublicclassUserController{//設(shè)置當(dāng)前請求方法為PUT魁袜,表示REST風(fēng)格中的修改操作@RequestMapping(value ="/users",method = RequestMethod.PUT)@ResponseBodypublicString update(@RequestBodyUser user) {? ? ? ? System.out.println("user update..."+ user);return"{'module':'user update'}";? ? }}

將請求路徑更改為?/users

訪問該方法使用 PUT:?http://localhost/users

訪問并攜帶參數(shù):

根據(jù)ID查詢

@ControllerpublicclassUserController{//設(shè)置當(dāng)前請求方法為GET,表示REST風(fēng)格中的查詢操作@RequestMapping(value ="/users/{id}",method = RequestMethod.GET)@ResponseBodypublicString getById(@PathVariableInteger id){? ? ? ? System.out.println("user getById..."+id);return"{'module':'user getById'}";? ? }}

將請求路徑更改為?/users

訪問該方法使用 GET:?http://localhost/users/666

查詢所有

@ControllerpublicclassUserController{//設(shè)置當(dāng)前請求方法為GET,表示REST風(fēng)格中的查詢操作@RequestMapping(value ="/users",method = RequestMethod.GET)@ResponseBodypublicString getAll() {? ? ? ? System.out.println("user getAll...");return"{'module':'user getAll'}";? ? }}

將請求路徑更改為?/users

訪問該方法使用 GET:?http://localhost/users

小結(jié)

RESTful入門案例峰弹,我們需要學(xué)習(xí)的內(nèi)容如下:

(1)設(shè)定Http請求動作(動詞)

@RequestMapping(value="",method = RequestMethod.POST|GET|PUT|DELETE)

(2)設(shè)定請求參數(shù)(路徑變量)

@RequestMapping(value="/users/{id}",method = RequestMethod.DELETE)

@ReponseBody

public String delete(@PathVariable Integer id){

}

知識點1:@PathVariable

名稱@PathVariable

類型形參注解

位置SpringMVC控制器方法形參定義前面

作用綁定路徑參數(shù)與處理器方法形參間的關(guān)系距境,要求路徑參數(shù)名與形參名一一對應(yīng)

關(guān)于接收參數(shù)三個注解?@RequestBody?、?@RequestParam?垮卓、?@PathVariable?,這三個注解之間的區(qū)別和應(yīng)用分別是什么?

區(qū)別

@RequestParam用于接收url地址傳參或表單傳參

@RequestBody用于接收json數(shù)據(jù)

@PathVariable用于接收路徑參數(shù)垫桂,使用{參數(shù)名稱}描述路徑參數(shù)

應(yīng)用

后期開發(fā)中,發(fā)送請求參數(shù)超過1個時粟按,以json格式為主诬滩,@RequestBody應(yīng)用較廣

如果發(fā)送非json格式數(shù)據(jù),選用@RequestParam接收請求參數(shù)

采用RESTful進(jìn)行開發(fā)灭将,當(dāng)參數(shù)數(shù)量較少時疼鸟,例如1個,可以采用@PathVariable接收請求路徑變量庙曙,通常用于傳遞id值

三空镜、RESTful快速開發(fā)

做完了RESTful的開發(fā),你會發(fā)現(xiàn)?好麻煩?捌朴,麻煩在哪?

每個方法的@RequestMapping注解中都定義了訪問路徑/books吴攒,重復(fù)性太高。

每個方法的@RequestMapping注解中都要使用method屬性定義請求方式砂蔽,重復(fù)性太高洼怔。

每個方法響應(yīng)json都需要加上@ResponseBody注解,重復(fù)性太高左驾。

對于上面所提的這三個問題镣隶,具體該如何解決?

@RestController//@Controller + ReponseBody@RequestMapping("/books")publicclassBookController{//@RequestMapping(method = RequestMethod.POST)@PostMappingpublicString save(@RequestBodyBook book){? ? ? ? System.out.println("book save..."+ book);return"{'module':'book save'}";? ? }//@RequestMapping(value = "/{id}",method = RequestMethod.DELETE)@DeleteMapping("/{id}")publicString delete(@PathVariableInteger id){? ? ? ? System.out.println("book delete..."+ id);return"{'module':'book delete'}";? ? }//@RequestMapping(method = RequestMethod.PUT)@PutMappingpublicString update(@RequestBodyBook book){? ? ? ? System.out.println("book update..."+ book);return"{'module':'book update'}";? ? }//@RequestMapping(value = "/{id}",method = RequestMethod.GET)@GetMapping("/{id}")publicString getById(@PathVariableInteger id){? ? ? ? System.out.println("book getById..."+ id);return"{'module':'book getById'}";? ? }//@RequestMapping(method = RequestMethod.GET)@GetMappingpublicString getAll(){? ? ? ? System.out.println("book getAll...");return"{'module':'book getAll'}";? ? }? ? }

對于剛才的問題,我們都有對應(yīng)的解決方案:

每個方法的@RequestMapping注解中都定義了訪問路徑/books诡右,重復(fù)性太高安岂。

將@RequestMapping提到類上面,用來定義所有方法共同的訪問路徑帆吻。

每個方法的@RequestMapping注解中都要使用method屬性定義請求方式域那,重復(fù)性太高。

使用@GetMapping@PostMapping@PutMapping@DeleteMapping代替

每個方法響應(yīng)json都需要加上@ResponseBody注解桅锄,重復(fù)性太高琉雳。

1.將ResponseBody提到類上面样眠,讓所有的方法都有@ResponseBody的功能2.使用@RestController注解替換@Controller與@ResponseBody注解友瘤,簡化書寫

知識點1:@RestController

名稱@RestController

類型類注解

位置基于SpringMVC的RESTful開發(fā)控制器類定義上方

作用設(shè)置當(dāng)前控制器類為RESTful風(fēng)格,?等同于@Controller與@ResponseBody兩個注解組合功能

知識點2:@GetMapping @PostMapping @PutMapping @DeleteMapping

名稱@GetMapping @PostMapping @PutMapping @DeleteMapping

類型方法注解

位置基于SpringMVC的RESTful開發(fā)控制器方法定義上方

作用設(shè)置當(dāng)前控制器方法請求訪問路徑與請求動作檐束,每種對應(yīng)一個請求動作辫秧,?例如@GetMapping對應(yīng)GET請求

相關(guān)屬性value(默認(rèn)):請求訪問路徑

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市被丧,隨后出現(xiàn)的幾起案子盟戏,更是在濱河造成了極大的恐慌绪妹,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,539評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件柿究,死亡現(xiàn)場離奇詭異邮旷,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)蝇摸,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,594評論 3 396
  • 文/潘曉璐 我一進(jìn)店門婶肩,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人貌夕,你說我怎么就攤上這事律歼。” “怎么了啡专?”我有些...
    開封第一講書人閱讀 165,871評論 0 356
  • 文/不壞的土叔 我叫張陵险毁,是天一觀的道長。 經(jīng)常有香客問我们童,道長畔况,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,963評論 1 295
  • 正文 為了忘掉前任慧库,我火速辦了婚禮问窃,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘完沪。我一直安慰自己域庇,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,984評論 6 393
  • 文/花漫 我一把揭開白布覆积。 她就那樣靜靜地躺著听皿,像睡著了一般。 火紅的嫁衣襯著肌膚如雪宽档。 梳的紋絲不亂的頭發(fā)上尉姨,一...
    開封第一講書人閱讀 51,763評論 1 307
  • 那天,我揣著相機(jī)與錄音吗冤,去河邊找鬼又厉。 笑死,一個胖子當(dāng)著我的面吹牛椎瘟,可吹牛的內(nèi)容都是我干的覆致。 我是一名探鬼主播,決...
    沈念sama閱讀 40,468評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼肺蔚,長吁一口氣:“原來是場噩夢啊……” “哼煌妈!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,357評論 0 276
  • 序言:老撾萬榮一對情侶失蹤璧诵,失蹤者是張志新(化名)和其女友劉穎汰蜘,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體之宿,經(jīng)...
    沈念sama閱讀 45,850評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡族操,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,002評論 3 338
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了比被。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片坪创。...
    茶點故事閱讀 40,144評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖姐赡,靈堂內(nèi)的尸體忽然破棺而出莱预,到底是詐尸還是另有隱情,我是刑警寧澤项滑,帶...
    沈念sama閱讀 35,823評論 5 346
  • 正文 年R本政府宣布依沮,位于F島的核電站,受9級特大地震影響枪狂,放射性物質(zhì)發(fā)生泄漏危喉。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,483評論 3 331
  • 文/蒙蒙 一州疾、第九天 我趴在偏房一處隱蔽的房頂上張望辜限。 院中可真熱鬧,春花似錦严蓖、人聲如沸薄嫡。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,026評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽毫深。三九已至,卻和暖如春毒姨,著一層夾襖步出監(jiān)牢的瞬間哑蔫,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,150評論 1 272
  • 我被黑心中介騙來泰國打工弧呐, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留闸迷,地道東北人。 一個月前我還...
    沈念sama閱讀 48,415評論 3 373
  • 正文 我出身青樓俘枫,卻偏偏與公主長得像腥沽,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子崩哩,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,092評論 2 355

推薦閱讀更多精彩內(nèi)容