angular學習筆記(二十八)-$http(6)-使用ngResource模塊構建RESTful架構

ngResource模塊是angular專門爲RESTful架構而設計的一個模塊,它提供了'$resource'模塊,$resource模塊是基於$http的一個封裝.下面來看看它的詳細用法html

1.引入angular-resource.min.js文件node

2.在模塊中依賴ngResourece,在服務中注入$resourcegit

var HttpREST = angular.module('HttpREST',['ngResource']);
HttpREST.factory('cardResource',function($resource){
    return $resource('/card/user/:userID/:id',{userID:123,id:'@id'},{charge:{method:'POST',params:{charge:true},isArray:false}})
});

3.$resource的參數:github

$resource(url,{url參數},{自定義方法})express

url: 必填,資源的基礎urljson

url中帶有 ':' 項的是根據第二個參數來進行配置的. 數組

url參數: 選填,配置url中的帶有 ':' 項的參數promise

eg: 架構

('/card/user/:userID/:id',{userID:123,id:'@id'}),那麼userID會被配置爲123.app

另外,在調用$resource()的方法的時候(好比get,query...),能夠傳入參數覆蓋這裏對url參數的配置,這在後面說獲得它的方法的時候再詳解

而id屬性在後面講第三個參數的時候講解

自定義方法: 

使用$resource獲取到的資源,或者經過$resource實例化的資源,資源自己會具備一些方法,好比$save,第三個參數用於給資源添加自定義的方法:詳見:http://www.cnblogs.com/liulangmao/p/3907032.html

4.$resource()的方法:

$resource()一共有如下5個方法:

get: 

{method:'GET'}

通常用於獲取某個資源:

query:

{method:'GET',isArray:true}

通常用於獲取一整套的資源,以數組形式返回

save:

{method:'POST'}

通常用於保存某個資源,有多是新建的資源,也有多是更新現有的資源

remove:

{method:'DELETE'}

通常用於刪除某個資源

delete:

{method:'DELETE'}

通常用於刪除某個資源

 

eg:

1.首先經過$resource建立一個服務:

var HttpREST = angular.module('HttpREST',['ngResource']);

HttpREST.factory('cardResource',function($resource){
    return $resource('/card/user/:userID/:id',{userID:123,id:'@id'},{charge:{method:'POST',params:{charge:true},isArray:false}})
});

這個cardResource服務,返回的是一個對象,對象有get,query,save,remove,delete五個方法

 

2.而後咱們經過cardResource這個服務,來建立另一個獲取資源的服務:

HttpREST.factory('httpCard',function($q,cardResource){
    return {
        getById:function(cardID){
            var defer = $q.defer();
            cardResource.get({id:cardID},function(data,headers){
                defer.resolve(data);
            },function(data,headers){
                defer.reject(data);
            });
            return defer.promise
        },
        query:function(){
            var defer = $q.defer();
            cardResource.query(function(data,headers){
                defer.resolve(data);
            },function(data,headers){
                defer.reject(data);
            });
            return defer.promise
        }
    }
});
httpCard這個服務返回的對象有兩個方法,一個getById方法,用於經過id加載資源,一個query方法,用於獲取所有的資源.

而後來說解一下get方法和query方法的用法:

get和query方法都是GET類型的請求,他們的調用方式是相同的:

cardResource.action([parameters], [success], [error])

[parameters]: 可選. 一個json對象,用於配置url裏的參數,好比這裏寫了{id:cardID},那麼提交的請求url就是 '/card/user/123/cardID'.

                    能夠不填,不填就直接按照$resource()裏的url來提交,注意,不填的話,不須要給個空,能夠直接寫success回調,angular可以判斷出它沒有填第一個參數,而不是死板的按照順序來解讀參數.

[success]:可選. 請求成功後的回調函數.回調接受2個參數(注意這裏和$http有所不一樣):

              function(data,headers){

              //data是請求到的內容

              //headers是響應頭

              }

[error]:可選. 請求失敗後的回調.回調接受1個參數

              function(httpResponse){

              //httpResponse暫不知道是什麼. 反正是和響應有關

              }

凡是經過$resource返回的對象,必定是json格式的,若是後臺返回的數據不是json,$resource也會按照本身的方式處理成json格式,好比後臺返回字符串'我愛你',那麼若是是get方法,獲得的數據就是:

{
0:我,
1:愛,
2:你
}

而query方法定義了isArray爲true,因此他的返回值必須是數組,而且數組裏的每一個值都必須是json格式的對象.若是返回的是字符串'我愛你',那麼若是是query方法,獲得的數據就是:

[

{0:'我'},

{0:'愛'},

{0:'你'}

]

若是返回的是一個json對象{name:'code_bunny'},那麼獲得的數據就是:

[{name:'code_bunny'}]

因此,在後臺最好就作好相應的處理,按照規範格式返回數據

 

3. 在控制器中使用httpCard服務來獲取資源:

HttpREST.controller('Card',function($scope,httpCard,cardResource){
    //經過id獲取銀行卡
    $scope.card_1 = httpCard.getById(1);
    $scope.card_2 = httpCard.getById(2);
    $scope.card_3 = httpCard.getById(3);
    //獲取全部的銀行卡
    $scope.cards = httpCard.query();

});
  <span>{{card_1['name']}}</span>
  <span>{{card_1['amount']}}</span>
  <br/>
  <span>{{card_2['name']}}</span>
  <span>{{card_2['amount']}}</span>
  <br/>
  <span>{{card_3['name']}}</span>
  <span>{{card_3['amount']}}</span>
  <br/>

node:

var cards = [
    {
        id:1,
        name:'建設銀行',
        amount:0
    },
    {
        id:2,
        name:'中國銀行',
        amount:0
    },
    {
        id:3,
        name:'上海銀行',
        amount:0
    }
];

app.get('/card/user/123/:id',function(req,res){
    var data = cards[req.params.id-1];
    setTimeout(function(){res.send(data)},2000)
});
app.get('/card/user/123',function(req,res){
    res.send(cards)
});

關於card_1...cards明明是promise對象,但視圖中卻正確顯示了資源的問題,請參考:http://www.cnblogs.com/liulangmao/p/3907307.html

  

4. 在控制器中使用cardResource服務的save方法來更新資源:

HttpREST.controller('Card',function($scope,httpCard,cardResource){
    $scope.card_3 = httpCard.getById(3);
    //更新id爲3的銀行卡
    $scope.updataCard = function(){
        $scope.card_3.then(function(data){
            data.name='工商銀行';
            cardResource.save(data);
            //data.$save()
        });
    };
});

  <button ng-click="updataCard()">更新id爲3的銀行卡</button>
  <br/>

<span>{{card_3['name']}}</span>
  <span>{{card_3['amount']}}</span>

node:(這段nodejs同時處理了charge和save)

var url = require('url');
app.post('/card/user/123/:id',function(req,res){ var index = req.params.id-1; var query = url.parse(req.url,true)['query']; if (query.charge){ cards[index]['amount']+= Number(query['amount']) } else { cards[index] = req.body; } res.send(cards[index]); });

  

點擊後→


cardResource.save(data) 和 data.$save()在這裏,二者是等價的.可是在有參數的時候,他們接受的參數實際上是不一樣的:

使用cardResource.save([parameters], postData, [success], [error])方法時,能夠接受四個參數:

[parameters]: 可選.用於配置url參數,好比配置{userID:124},那麼請求url就會變成 'card/user/124/3',其中的3,仍是從請求體的id屬性獲取的.

                    一樣,若是沒有參數須要配置,是不要填空的.不存在順序一一對應.能夠直接把postData做爲第一個參數.

postData: 必填. 發送的請求體. save方法是post請求,必需要帶有請求體.

[success]:選填. 響應成功後的回調函數,參數同get方法成功回調裏的參數

[error]:選填. 響應失敗後的回調函數.參數同get方法失敗回調裏的參數

使用data.$save([parameters], [success], [error])方法時,能夠接受三個參數:

[parameters]: 可選.注意它不是用於配置url的參數的.它是用來設置url?後面的參數的! 好比設置{name:'code_bunny'},那麼請求url就會變成'card/user/123/3?name=code_bunny',

                    經過$save方法來調用save方法,是不可以配置url參數的.它直接就是提交資源本身.

                    一樣,若是沒有參數須要配置,是不要填空的.不存在順序一一對應.能夠直接把[success]做爲第一個參數.

[success]:選填. 響應成功後的回調函數,參數同get方法成功回調裏的參數

[error]:選填. 響應失敗後的回調函數.參數同get方法失敗回調裏的參數

至於爲何要在then回調裏處理,爲何save後視圖會自動更新,請查看:http://www.cnblogs.com/liulangmao/p/3907307.html 以及 http://www.cnblogs.com/liulangmao/p/3907032.html

 

5. 在控制器中使用cardResource服務的save方法來新建資源:

(1)新建帶有id的資源:

    //添加id爲4的銀行卡
    $scope.addCard4 = function(){
        var card_4 = new cardResource();
        card_4['id'] = 4;
        card_4['name'] = '浦發銀行';
        card_4['amount'] = 0;
        card_4.$save(function(data){$scope.card_4=data});
//cardResource.save(card_4,function(data){$scope.card_4=data}); };
  <span>{{card_4['name']}}</span>
  <span>{{card_4['amount']}}</span>

node:(這段nodejs同時處理了charge和save)

app.post('/card/user/123/:id',function(req,res){
    var index = req.params.id-1;
    var query = url.parse(req.url,true)['query'];
    if (query.charge){
        cards[index]['amount']+= Number(query['amount'])
    }
    else {
        cards[index] = req.body;
    }
    res.send(cards[index]);
});

點擊後→

新建資源須要經過new cardResource(), 這樣它就是$resource()的實例,就擁有了$save,$charge等資源的方法:

card_4.$save(function(data){$scope.card_4=data});

cardResource.save(card_4,function(data){$scope.card_4=data});

上面已經說過了,這兩種寫法天然是等價的.但這裏的回調裏須要給$scope_card_4進行賦值,由於原來的$scope下是沒有card_4這個變量的.

(2)新建沒有id的資源:

    //添加沒有id的銀行卡
    $scope.addCard = function(){
        var newCard = new cardResource();
        newCard['name'] = '農業銀行';
        newCard['amount'] = 0;
        newCard.$save(function(data){$scope.card_5=data});
cardResource.save(newCard,function(data){$scope.card_5=data});
//newCard.$save(function(data){$scope.card_5=data});
    };
<button ng-click="addCard()">添加一張不指定id的銀行卡</button>
<br/>
<span>{{card_5['name']}}</span>
<span>{{card_5['amount']}}</span>

node:

app.post('/card/user/123',function(req,res){
    var index = cards.length;
    cards[index] = req.body;
    res.send(cards[index]);
});

點擊後→


cardResource.save(newCard,function(data){$scope.card_5=data});
newCard.$save(function(data){$scope.card_5=data});
上面已經說過了,這兩種寫法天然是等價的.但這裏的回調裏須要給$scope_card_5進行賦值,由於原來的$scope下是沒有card_5這個變量的.

 (1)和(2)的區別在於:

  資源是否有id,他們請求的路徑是不一樣的.沒有id的資源會請求'card/user/123',而有id的資源會請求'card/user/123/id',這在node裏的處理是不一樣的.

  在$resource中,基本url裏面的 :id 這類經過參數指定的值,若是沒有傳入參數,那麼它提交的路徑裏就不會包含這一項,好比:

  return $resource('/card/user/:userID/:id',{userID:123,id:'@id'})
  當使用query方法時,是沒有id值的,get請求的路徑就是/card/user/123

  可是在node裏面不是這樣的:

app.get('/card/user/123/:id',function(req,res){
//這個只能處理帶有id值的get請求,沒有id請求不能被匹配處處理
});
app.get('/card/user/123',function(req,res){
//這個用來處理沒有id的get請求
});
app.post('/card/user/123/:id',function(req,res){
//這個只能處理帶有id值的post請求,沒有id請求不能被匹配處處理
});
app.post('/card/user/123',function(req,res){
//這個用來處理沒有id的post請求
});

因此,處理有id的資源的post請求和處理沒有id的資源的post請求,在node裏須要寫不一樣的匹配規則,在這裏,對於沒有id的資源,咱們僅做模擬,就把它按照順序保存在數組最後,而後固然仍是把它返回給客戶端.

 

6. 在控制器中使用cardResource服務的自定義的charge方法來給資源進行充值操做:

    //id爲1的建設銀行卡增長100元
    $scope.addCharge = function(){
        $scope.card_1.then(function(card){
            card.$charge({amount:100});
        })
    }
  <button ng-click="addCharge()">給建設銀行的卡充值100元</button>
  <br/>
  <span>{{card_1['name']}}</span>
  <span>{{card_1['amount']}}</span>

node:(這段nodejs同時處理了charge和save)

app.post('/card/user/123/:id',function(req,res){
    var index = req.params.id-1;
    var query = url.parse(req.url,true)['query'];
    if (query.charge){
        cards[index]['amount']+= Number(query['amount'])
    }
    else {
        cards[index] = req.body;
    }
    res.send(cards[index]);
});

這裏的charge充值方法須要帶有請求參數,?amount=100,因此它不能使用cardResource.charge([params],data,[success],[error])這種方式來請求,只能經過調用資源自身的$charge方法來進行請求.

card.$charge({amount:100})至關於請求了url: 'card/user/123/1?charge=true&amount=100'

即便是RESTful架構,不表示就不能夠在url中帶有參數,帶有參數不影響express對路徑的匹配.獲取路徑參數的方法也就是使用url模塊同樣獲取.
不管POST請求仍是GET請求,均可以帶有參數,也均可以獲取參數.

這裏對'/card/user/123/:id'這個url的請求作了判斷,獲取它的參數,而後判斷參數裏的charge是否等於true,是的話表示充值操做.不是的話表示更新資源操做.分別對資源進行處理,最後都是把操做過的資源返回給客戶端.

其中,url.parse(req.url,true),若是不帶有true,不會把參數解析成json格式.

點擊後→

 

7. 在控制器中使用cardResource服務的delete方法來刪除資源:

    //刪除id爲1的銀行卡
    $scope.delCard1 = function(){
        $scope.card_1.then(function(card){
            card.$delete();
        })
    }
  <button ng-click="delCard1()">將id爲1的銀行卡刪掉</button>
  <br/>
  <span>{{card_1['name']}}</span>
  <span>{{card_1['amount']}}</span>

node:

app.delete('/card/user/123/:id',function(req,res){
    var index = req.params.id-1;
    cards[index] = null;
    res.send({})
});

點擊後→

這裏有兩點須要注意:

1.card.$delete()不等同於cardResource.delete(card),由於它這裏是'DELETE'方式的請求,不是POST方式的請求,當咱們使用card.$delete()的時候,它是把card做爲請求體發送給後臺的(至關於POST請求體).可是當咱們使用cardResource.delete(card)的時候,它是把card對象解析成url參數一塊兒傳給後臺的(至關於GET請求裏url後面的參數).也就是說,card.$delete()請求的url是'card/user/123/1',附帶請求體爲card. 而cardResource.delete(card)請求的url是'card/user/123/1?amount=0&name=建設銀行'.

還有很重要的一點,其實請求url是'card/user/123/1?amount=0&name=建設銀行'在這個例子中並不會改變後臺的處理和返回,可是對於angular來講,card.$delete()會使用返回值去填充card,更新視圖,可是cardResource.delete(card),它並不是請求體就是card,因此返回值不會去填充card,不會更新視圖.因此,在使用delete方法時,應該直接使用$delete,而不是delete.(remove亦然)

2.刪除之後,cards[0]就變成空的null,可是不能返回null,由於$resource必須返回json格式,因此要返回{}

 

完整代碼地址:https://github.com/OOP-Code-Bunny/angular/tree/master/OREILLY/18.6%20%24http(ngResource)

相關文章
相關標籤/搜索