1.AngularJS中的 $resource
這個服務能夠建立一個資源對象,咱們能夠用它很是方便地同支持RESTful的服務端數據源進行交互,當同支持RESTful的數據模型一塊兒工做時,它就派上用場了。
REST是Representational State Transfer(表徵狀態轉移)的縮寫,是服務器用來智能化地提供數據服務的一種方式
javascript
1)咱們首先須要引入ng-Resource 模塊,在angular以後html
<script src="js/vendor/angular.js"></script><script src="js/vendor/angular-resource.js"></script>java
2) 在咱們的應用中須要將其當作依賴進行引用
angular.module('myApp', ['ngResource']);
3)如何使用?
$resource服務自己是一個建立資源對象的工廠,返回的$resource對象中包含了同後端服務器進行的交互的高層API.
var User=$resource('/api/users/:userId',{userId:'@id'});
能夠把User對象理解成同RESTful的後端服務進行交互的接口。angularjs
【HTTP GET類型的方法】
①GET請求: get(params,successFn,errrorFn)web
不定義具體的參數,get()請求一般被用來獲取單個資源。ajax
//GET /api/users
User.get(function(resp){
//處理成功
},function(err){
//處理錯誤
});
若是參數中傳入了具名參數(咱們例子中的參數是id),那麼get()方法會向包含id的URL發送請求:
//發起一個請求:GET-->/api/users/123
User.get({id:'1234'},function(resp){
//success
},function(error){
//fail
});
②QUERY 請求:query向指定URL發送一個GET請求,並指望返回一個JSON格式的資源對象集合。
//發起一個請求
User.query(function(users){
//讀取集合中的第一個用戶
var user=users[0];
});
query()和get()方法之間惟一的區別是AngularJS指望query()方法返回數組。
【非HTTP GET類型的方法】
1. save(params, payload, successFn, errorFn)save方法向指定URL發送一個POST請求,並用數據體來生成請求體。save()方法用來在服務器上生成一個新的資源。 payload:表明請求發送的數據體
//發送一個請求 with the body {name: 'Ari'}spring
User.save({},{name:'Ari'},function(resp){},function(error){
});
2. delete(params, payload, successFn, errorFn)
delete方法會向指定URL發送一個DELETE請求,並用數據體來生成請求體。它被用來在服務器上刪除一個實例:
// DELETE /api/users
User.delete({}, {
id: '123'
}, function(response) {
// 處理成功的刪除響應
}, function(response) {
// 處理非成功的刪除響應
});
3. remove(params, payload, successFn, errorFn)
remove方法和delete()方法的做用是徹底相同的,它存在的意義是由於delete是JavaScript的保留字,在IE瀏覽器中會致使額外的問題。
// 發起一個請求:
// DELETE /api/users
User.remove({}, {
id: '123'
}, function(response) {
// 處理成功的刪除響應
}, function(response) {
// 處理非成功的刪除響應
});
2.$resource Restful api 與 ngResoruce
$http服務提供了一個很是低級的實現,能夠用來發送XHR請求,同時它還爲你提供了很大的可控性和靈活性。可是,在大多數狀況下,咱們須要處理對象,以及封裝了特定屬性和方法的對象模型,例如一個person對象(帶有詳細信息),或者一個信用卡對象。shell
在這些狀況下,若是咱們可以建立一個JS對象,並且它能夠理解並表明這種對象模型,是否是會很棒?若是咱們僅僅編輯這個對象的屬性,例如保存或者更新,那麼這些狀態會被持久化到服務端嗎?數據庫
$resource就是爲這一功能而設計的。AngularJS中的resource(資源)容許咱們用描述性的方式來定義對象模型,它能夠描述如下內容:c#
1.資源在服務端的URL。
2.經常使用的請求參數類型。
3.一些附加的方法(你能夠自動得到get、save、query、remove和delete方法),這些方法爲對象模型包裝了特定的功能和業務邏輯(例如信用卡對象的charge()方法)。
4.指望得到的響應類型(一個數組或者一個對象)。
5.協議頭。
使用Angular所提供的$resource對象,你能夠根據各類需求查詢服務器;除此以外,你還能夠把服務端返回的對象當成已經持久好的數據模型,你能夠修改它們,而且能夠把它們持久化。
ngResource是一個獨立的、可選的模塊。爲了使用它,須要:
a.在加載的腳本文件中包含angular-resource.js
b.在模塊依賴聲明中包含ngResource(例如,angular.module('myModule', ['ngResource']))。
c.在須要的地方使用注入的$resource服務。
在學習如何使用ngResource方法建立資源以前,咱們先來看看使用基本的$http服務建立相似的東西須要作些什麼事情。對於咱們的信用卡資源來講,除了要可以對它進行"change"(收費)操做以外,咱們還要可以get(獲取)、query(查詢)以及save(保存)信用卡。
如下是一種可能的實現:
myAppModule.factory('CreditCard', ['http', function($http) { var baseUrl = '/user/123/card'; return { get: function(cardId) { return $http.get(baseUrl + '/' + cardId); }, save: function(card) { var url = card.id ? baseUrl + '/' + card.id : baseUrl; return $http.post(url, card); }, query: function() { return $http.get(baseUrl); }, charge: function(card) { return $http.post(baseUrl + '/' + card.id, card, {params: {charge: true}}); } }; }]);
除了這種方式以外,還能夠簡單地建立一個Angular服務,這個服務將會經過如下方式來描述應用所提供的資源:
myAppModule.factory('CreditCard', ['$resource', function($resource) { return $resource('/usr/:userId/card/:cardId', {userId: 123, cardId: '@id'}, {charge: {method: 'POST', params: {charge: true}, isArray: false}); }]);
如今,只要向咱們AngularJS注射器請求一個CreditCard實例,咱們就能夠獲取一個Angular資源,它默認爲咱們提供了一些基礎的方法。下表列出了這些方法的內容以及它們的行爲,有了這些信息你就知道應該如何配置服務端了。 下面咱們來看一個信用卡的實例,這會讓咱們的思路更加清晰。
//假設CreditCard服務被注入到了這裏 //咱們能夠從服務端獲取一個集合,請求的路徑爲GET:/user/123/card var cards = CreditCard.query();
//咱們還能夠在回調函數中獲取並使用單張信用卡 CreditCard.get({cardId: 456}, function(card) { //每一個實例都是CreditCard類型 expect(card instanceof CreditCard).toEqual(true); card.name ="J.Smith"; //非GET型的方法被映射到了實例上 card.$save(); //咱們自定義的方法也被映射上去了 card.$charge({amount:9.99}); //發起一個POST請求:/user/123/card/456?amount=9.99&charge=true //發送請求時傳遞的數據爲:{id:456, number: '1234', name: 'J.Smith'} });
這個例子涉及了比較多的內容,對於其中比較重要的內容依次介紹以下:
一.聲明
不管是自已定義$resource,仍是使用正確的參數來調用注入的$resource函數,操做都很是簡單。
$resource函數有一個必需的參數,便可用資源的URL地址,還有兩個可選的參數,即默認參數以及你想配置在資源上的額外動做。
請注意URL是參數化的(用:來標識參數。:userId表示userId將會被替換成對應的文本,:cardId表示將會被cardId實參的值替換掉)。若是沒有傳遞參數,對應的標識符會被替換成空字符串。
第二個參數負責處理每個請求中都會被髮送的默認值。在當前這個例子中,咱們會把常量123傳遞給userId。參數cardId更加有趣,「cardId是"@id."」表示的是,若是咱們正在使用一個從服務端返回的對象,那麼當調用這個對象上的任意方法時(例如調用對象的$save方法),對象上的id屬性值就會被賦給cardId參數。
第三個參數是另外一個函數,咱們但願在自定義的資源上暴露這個函數。
二.自定義方法
調用$resource時,傳遞的第三個參數是一個可選的。咱們但願在自已的資源上暴露的方法。
在前面的例子中,咱們指定了一個charge方法,能夠經過傳遞一個對象來配置這個方法,對象中的key就是須要暴露的方法名稱。配置項中須要指定的內容有:請求的類型(GET、POST等)、須要做爲請求的一部分來傳遞的參數(在這個例子中就是charge=true),以及返回的結果是不是一個數組(在這個例子中不是)。一旦作完這些事情以後,你就能夠自由地調用CreditCard.charge()了
說明:這是一種很是靈活的編碼風格,根據上面的代碼,對於配置對象{charge: {method: 'POST', params: {charge: true}, isArray: false},Angular會將其解析成一個方法,而後把這個方法綁定到返回的Restful對象上,上面的配置對象解釋以後的方法爲:
CreditCard.charge = function(charge, isArray) { //這裏是方法體 }
三.別用回調!(除非你真的須要它們)
第三個須要注意的內容是調用資源時的返回值類型。請再看一下CreditCard.query()調用,咱們直接把信用卡對象賦值給了card變量,而並無在回調函數裏面進和賦值。你可能會擔憂在對服務器進行異步請求的狀況下,這種代碼能運行嗎?
你這種擔憂是合理的。但事實上,這段代碼徹底正確,而且可以運行。這裏發生的事情是,AngularJS賦給了card對象一個引用(一個對象或者數組,具體是什麼須要根據所指望的返回值類型而定),在將來的某個時間上,當對服務器的請求返回來以後,這個引用纔會被真正賦值。在些期間,引用對象一直是空的。
對於AngularJS應用來講,最多見的處理流程是:到服務器上獲取數據,而後把數據賦值給變量,再把數據顯示到模板中。這種快捷方式是很是好用的。在控制器代碼中,你惟一要作的事情就是發起對服務端的調用,把返回值賦給正確的做用域變量,而後讓模板自動負責渲染它。因爲card變量是使用{{}}這種數據綁定技術綁定到視圖上的,因此一開始給它一個空值並無問題,等異步響應返回以後再把結果賦給它。這時候Angular的數據綁定機制會當即發現數據發生了變化,而後會自動通知視圖進行刷新。從這裏能夠看到,使用Angular框架時,對異步調用的不少處理方式已經發生了細微的變化。
若是你有一些須要依賴於返回值才能執行的業務邏輯,那麼這種方法就不會奏效。在這種狀況下,你就須要使用回調函數,這個回調函數會在調用CreditCard.get()的時候被使用。
四.簡化服務端操做
不管你使用返回值的快捷方式,仍是使用回調函數,都有一些關於返回對象的注意事項。返回值不是普通的JS對象,而是一個"resource"型的對象。這就意味着,除了服務端返回的數據以外,它上面還帶有一些附加的行爲(在這個例子中就是$save()和$charge())。這樣可讓你更容易進行服務端調用,例如獲取數據、修改數據,以及把修改的內容持久化到服務端(也就是在不少應用中都很常見的CRUD操做)。
五.什麼時候可使用Angular資源
只有服務端按照RESTful的方式工做的時候,你纔可使用Angular資源。對於信用卡場景,它須要:
1.一個到/user/123/card的GET請求,它會返回用戶123的信用卡列表。
2.一個到/user/123/card/15的GET請求,它會返回用戶123的ID爲15的信用卡。
3.一個到/user/123/card的POST請求,在POST的數據中帶有信用卡信息,它將會爲用戶123的ID建立一張新的信用卡。
4.一個到/user/123/card/15的POST請求,POST的數據中帶有信用卡信息,它將會更新用戶123的ID爲15的信用卡信息。
5.一個到/user/123/card/15的DELETE請求,它將會刪除用戶123的ID爲15的信用卡信息。
我發現一個Angular JS中的關鍵問題是(以我喜歡的代碼工做方式來講)$save方法在ngResource中將只會使用POST沿着有效載荷提交到服務器。新建和更新記錄操做都是這樣的,對來自服務器的新和舊的對象都是如此。這破壞了 RESTful約定的更新操做應該使用PUT或者PATCH操做。我下面建議的解決方案拓展了現有的ngResource實現,提供了更多的默認選項,同時精簡了咱們的工做流程。完美的用法(恕我直言)應該像下面這樣:
1
2
3
4
5
6
7
|
var
user =
new
User;
user.name =
'Kirk Bushell'
;
user.$save();
// POST
var
user = User.get( { id: 1 });
user.name =
'John smith'
;
user.$save();
// PUT
|
若是咱們深刻ngResource的代碼中,這樣的需求是可能的,關於怎麼樣去簡化它的實現(這應該是由 Angular 的團隊來完成)。不幸的是,它的確意味着若是咱們想要同時用POST/PUT來實現保存操做,咱們不得不用兩個不一樣的方法(這不是個人風格)。恕我直言,保存就是保存 --- 讓你的模塊/類 來定義這是什麼樣的保存(新建或是更新)操做。咱們須要作的是用咱們本身的默認實現來拓展ngResource提供的 $resource工廠。讓咱們接着看下去。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
var
module = angular.module(
'my.resource'
, [
'ngResource'
] );
module.factory(
'Resource'
, [
'$resource'
,
function
( $resource ) {
return
function
( url, params, methods ) {
var
defaults = {
update: { method:
'put'
, isArray:
false
},
create: { method:
'post'
}
};
methods = angular.extend( defaults, methods );
var
resource = $resource( url, params, methods );
resource.prototype.$save =
function
() {
if
( !
this
.id ) {
return
this
.$create();
}
else
{
return
this
.$update();
}
};
return
resource;
};
}]);
|
這裏咱們定義了一個自定義模塊 - my.resource,這個模塊能夠被注入到其餘你想要這個拓展功能的模塊中。咱們接着以一個依賴爲咱們的Resource工廠注入$resource,並作一些小魔法,讓咱們研究下吧。
首先,咱們定義了一個新的默認數組。它包括了爲resource的更新update和新建create方法 - create方法將會被定義成一個POST請求,update方法將會被定義成一個PUT請求。咱們爲何會想要這兩個額外的方法?由於它容許咱們作更明確的請求,正因如此,咱們須要重載$save方法!
咱們拓展了任何咱們會提供給resource的方法。而後,咱們定義咱們的新resource和經過重載$save方法拓展它。這個方法會檢查id字段是否包含在一個資源對象中,若是有id字段,它將會調用咱們定義在default中的$update方法;若是沒有id字段,它會調用$create方法,很簡單吧!
可是 - 咱們怎麼在咱們本身的資源中使用它呢?小菜一碟。
1
2
3
4
5
|
var
module = angular.module(
'services'
, [
'my.resource'
] );
module.factory(
'User'
, [
'Resource'
,
function
( $resource ) {
return
$resource(
'users/:id'
, { id:
'@id'
} );
}]);
|
如今你能夠看到 - 咱們對待它就像對待其餘的資源同樣注入,惟一的區別是 - 咱們定義了咱們的 $resource依賴於咱們本身進行拓展ngResource 後的Resource。
3.AngularJS Resource 與 Restful API的交互
REST(表徵性狀態傳輸,Representational State Transfer)是Roy Fielding博士在2000年他的博士論文中提出來的一種軟件架構風格。RESTful風格的設計不只具備更好的可讀性(Human Readable),並且易於作緩存以及服務器擴展(scalability)。REST風格體如今URL設計上:
- 每一個URL對應一個資源
- 對資源的不一樣操做對應於HTTP的不一樣方法
- 資源表現形式(representation)經過
Accept
和Content-Type
指定
AngularJS提供了$resource
Service來更方便地與RESTful服務器API進行交互,能夠方便地定義一個REST資源,而沒必要手動全部的聲明CRUD方法。
參考文檔: https://docs.angularjs.org/api/ngResource/service/$resource
Resource Factory
$resource
Service定義在ngResource
Module中,須要在你的HTML中引入這個Module對應的JS,同時在你的APP中添加這樣一個依賴:
var app = angular.module('helloApp, ['ngResource']);
而後爲資源創建一個Factory:
app.factory('Notes', ['$resource', function($resource) { return $resource('/notes/:id'); }]);
固然,你也能夠不把
$esource
的實例放到Factory裏,直接在控制器中存起來:var Notes = $resource('/notes/:id)
。
CRUD
在你的控制器中就能夠對資源進行增刪改查了:
app.controller('NotesCtrl', ['$scope', 'Notes', function($scope, Notes) { var notes = Notes.query(function(){ // GET: /notes // Response: [{id: 1, content: 'hello'}, {id: 2, content: 'world'}]; var first = notes[0]; first.content = 'halo'; first.$save(); // POST: /notes/1 {id: 1, content: 'halo'} // Response: {id: 1, content: 'halo'} second.$delete(); // DELETE: /notes/2 }); var note = new Notes({content: 'xxx'}); note.$save(); // POST: /notes // Response: {id: 3, content: 'xxx'} }]);
PUT 操做
$resource
提供了五種默認操做:get
, query
, save
, remove
, delete
。你能夠配置一個update
操做來完成HTTP PUT:
app.factory('Notes', ['$resource', function($resource) { return $resource('/notes/:id', null, { update: { method:'PUT' } }); }]);
如今,你能夠在控制器中獲取一個note並更新它:
var note = Notes.get({ id: 3}), $id = note.id; note.content = 'yyy'; Notes.update({ id:$id }, note); // PUT /notes/3 {id: 3, content: 'yyy'}
如今你的Notes
有六種操做了。這些操做有兩種調用方式:
- 經過資源類調用,例如:
Notes.update({id: xxx})
; - 經過資源實例調用,例如:
note.$update()
,此時操做名需加前綴$
。
具體的調用參數可參考文檔:
HTTP GET "class" actions: Resource.action([parameters], [success], [error])
non-GET "class" actions: Resource.action([parameters], postData, [success], [error])
non-GET instance actions: instance.$action([parameters], [success], [error])
其中,success參數爲(value, responseHeaders)
,error參數爲(httpResponse)
。
屬性/URL映射
上述例子中,咱們看到note對象的id
屬性會映射到URL中的:id
(/notes/:id
)。若是你的業務更加複雜,能夠手動配置這個映射關係。例如:
var Notes = $resouce('/users/:userId/notes/:noteId', { noteId: '@id', userId: '@owner' }
將會讀取note
的owner
和id
屬性來生成URL,好比刪除note時:
// note === {id: 123, owner: 'alice', content: 'hello'} note.$delete(); // DELETE: /users/alice/notes/123
在構造$resource
時,多於的屬性映射會成爲URL Query。例如:
var Notes = $resouce('/notes/:id', { id: '@id', user: '@owner' }); // note === {id: 123, owner: 'alice', content: 'hello'} note.$delete(); // DELETE: /notes/123?user=alice
REST操做的聲明和調用中,多於的屬性會成爲URL Query。例如:
var Notes = $resouce('/notes/:id', {id: '@id'}, { update: {method: 'PUT', operator: 'bob'} }); // note === {id: 123, content: 'hello'} note.$update({trusted: true}); // PUT: /notes/123?operator=bob&trusted=true {id: 123, content: 'hello'}
響應轉換
有時基於既定的後臺設計,沒法提供徹底RESTful的API,好比/notes
返回的是一個分頁器對象,而非數組。此時,咱們仍然可使用$resource
,但須要設置響應轉換回調。例如:
var Notes = $resouce('/notes/:id', null, { pager: { method: 'GET', transformResponse: function(data, headers){ // Server respond: // data = {currentPage: 1, // totalPage: 20, // pageSize: 2, // content: [{id: 1, content: 'hello'}, {id: 2, content: 'world'}]} var pager = JSON.parse(data); return pager.content; } } }); var notes = Notes.query(function(){ // GET: /notes // notes === [{id: 1, content: 'hello'}, {id: 2, content: 'world'}] });
相似響應重寫,你還能夠設置請求轉換transformRequest
。
雖然
$resource
的設計能夠支持絕大多數的URL和內容表示設計,但若是你發現$resource
的使用過程極其複雜,那多是你的服務器API並不知足RESTful風格。
摘自: http://harttle.com/2015/06/05/angular-resource.html
4.AngularJS 使用 ngResource、Restful API 和Spring MVC 交互
本文爲開發者呈現了一些概念和相關的示例代碼,介紹了用ngResource($resource)服務POST方式提交數據到和服務器端SpringMVC環境下的RESTFul APIs。示例代碼能夠在以下頁面找到:http://hello-angularjs.appspot.com/angularjs-restful-apis-post-method-code-example。相對於使用$http服務,我更喜歡這種方法的主要理由是ngResource容許你使用抽象方式(例如$resource類),你可使用它的實例上的處理方法與RESTFul APIs交互。這樣就能夠簡單方便地實現RESTFul集成。在$resource類的對象上,能夠直接調用處理方法(例如get、save等)。所以,在其實例上,就可使用"$"做爲前綴直接調用這些方法。具體的例子以下所示。 |
kimmking
|
這篇文章裏,用如下兩個情景用例來解釋:
代碼片斷包含了AngularJs代碼和Spring MVC代碼,以可以讓你簡單快速的上手。 想要$resource 服務工做,須要添加一段實際代碼: 應用angular-resource.js文件,你可使用Google Hosted Libraries來實現。 下面採用的代碼是最新的angularJs版本。(下面就是引入服務的代碼)
下面的代碼告訴你如何在建立控制器時引入ngResource模塊和注入$resource服務:
保存/持久化新對象 (其實就是傳給後臺存進數據庫的一個過程) 下面的代碼演示瞭如何使用POST方法提交form表單中的user信息(這部分是由controller來作),controller會把uers信息提交給REST URL 「/user/new」(這部分是Spring MVC的控制器執行)。 |
神棍局王某
|
AngularJS代碼
Spring MVC 代碼 請注意User對象的字段要和JSON數據的要一致。同時確保Jackson包已經引入了,而且正常工做了。這是最重要的步驟。我推薦參考這篇文章 how to fix 415 Unsupported Mediatype error 來幫助你實現前面兩個步驟。(1.Spring轉對象的時候,是按照字段名來轉的,好比你的Java的User對象的firstname會綁定Json對象的firstname,因此須要保持一致,不然幫出來的數據可能不對。2.不引人Jackson包,那麼Json對象和Java對象不能想換轉化,也就不能正常工做了)
更新已存在的數據對象 下面的代碼演示瞭如何經過POST方法提交表單信息來更新user對象,請求會發送到服務器的REST URL "/user/{id}",也包括Spring MVC的方法。 |
神棍局王某
|
AngularJS代碼
Spring MVC 代碼 請注意下面幾點 -用例的路徑變量(就是"/user/{id}"這東西) -Java的User對象要和Json對象匹配(字段名,或者說是屬性名) -確保Jackson包引入而且正常工做(確保你後臺能正常轉化Json和java對象)
|
神棍局王某
|
0個評論