AngularJS实际项目应用——Service层介绍

所谓的Service层就是如何调用后台的rest api,你可能觉得这有什么可设计的?不就是用$http或者$resource直接调用就行了吗?如果这样写,在简单的应用中还行,但程序一旦复杂起来,$http调用会散落在各种controller或者directive中,会有很多重复的代码。如果后台rest api的路径设计不好的话,那通过$http调用会使得业务逻辑很难被理解。万一需要更改路径,只能全局检索了。综上所述,需要设计一个统一的service调用层,把rest api调用封装在里面,下面看看怎么设计。

首先会把service按照业务逻辑进行划分,每个模块下都会有一个.service.js的文件:

AngularJS实际项目应用——Service层介绍_第1张图片

接着有两种service的设计方法,一种是创建一个单独的service module,叫app.services,然后把每个业务模块下的service都挂到这个模块下;还有一种是把每个业务模块下的service挂到自己的module下。


先看单独service module的实现:

define(["require","angular"], function(require,ng) { 
	var ser=angular.module('app.services',[])
    .config([
			'$controllerProvider',
			'$compileProvider',
			'$filterProvider',
			'$provide',
			function( $controllerProvider, $compileProvider, $filterProvider, $provide){
				ser.controller = $controllerProvider.register;
				ser.directive  = $compileProvider.directive;
				ser.filter     = $filterProvider.register;
				ser.factory    = $provide.factory;
				ser.service    = $provide.service;
			}
    ]); 
	return ser;
});
把上面的代码放到一个js文件里,然后在app.js里用define加载进来,并且加到app module的依赖中去。

在看某一个业务逻辑service文件里面怎么写:

define(['require','angular'], function(require,ng){
    var module=ng.module('app.services');//这里直接通过ng.module引用,因为app.services在app启动的时候就已经load进来了
    module.factory('personSrv',['httpUtils',function(httpUtils){ 
    	var urls = {
				"modify": globalConfig.apiUrl + "admin/password"
			}
			
			var funcs = {
				"modifyPassword" : modifyPassword
			};
			
			return funcs;

			function modifyPassword(params){
				return httpUtils.httpPut(urls.modify,params);
			}
			
    }]);
});
接着看controller里如何用这个service:

define(['require','angular',"person/person.service"], function(require,ng){
    var module=ng.module('app.person');
    module.controller('ChangePwdCtrl',['$scope','$filter','$state','$uibModalInstance','personSrv',
        function($scope,$filter,$state,$uibModalInstance,personSrv){

			$scope.ok = function (isValid){
				if(isValid){
					personSrv.modifyPassword({......}).then(function(){
					});
					
				}
			}
        	
        }
    ]); 

    return module;
});
通过上面的流程,看到service如何被调用的了,这样设计的好处就是可以在需要的controller里面很方便的引用需要的service,并且在调用的时候使用personSrv.modifyPassword()这种形式,简单明了的知道这个api是处理什么业务的。


再看把service挂到自己的业务逻辑模块下:

这样设计其实就是省了一个app.services模块文件,但是写真正service的时候需要特殊处理一下,还继续拿上面的例子

define(['require','angular',"ngload!person.module"], function(require,ng,module){//这里需要通过ngload动态把module加进来
    module.factory('personSrv',['httpUtils',function(httpUtils){ 
    	var urls = {
				"modify": globalConfig.apiUrl + "admin/password"
			}
			
			var funcs = {
				"modifyPassword" : modifyPassword
			};
			
			return funcs;

			function modifyPassword(params){
				return httpUtils.httpPut(urls.modify,params);
			}
			
    }]);
});
有两点需要注意,1)需要通过ngload调用,不能直接在define里写person.module,因为ngload会处理angular module里面定义的config,run等方法,如果直接define进来,那些config,run方法就不会被调用了。2)这里不能用ng.module("app.person")这种写法,因为如果其他模块引用了这个service文件,那时app.person.module.js文件还没有被加载进来呢,就会报错。所以这里必须通过ngload来搞。


两种方法应该都行,但在单元测试的时候,用第一种方法应该会省很多麻烦,所以本应用采用了第一种方法设计的service层。



你可能感兴趣的:(AngularJS)