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个评论