首页> 搜索结果页
"AngularJS服务service用法总结" 检索
共 9 条结果
AngularJS服务总结
在之前介绍AngularJS的博客中,简单的介绍了AngularJS提供的常用服务,以及如何自定义服务,具体可参见《AngularJS 服务(Service)》。在这一篇博客中,我将为大家详细介绍如何自定义服务,以及各种方式之间的区别。 value(name, object) value(name, object)方法允许我们直接将一个普通值或对象作为服务。我们通过一段代码来看看如何使用: <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title>AngularJS</title> <script type="text/javascript" src="js/angular.min.js"></script> <script type="text/javascript"> angular.module("myApp", []) .value("HQValue", 10) .controller("myCtrl", function($scope, HQValue) { $scope.value = HQValue; }); </script> </head> <body ng-app="myApp" ng-controller="myCtrl"> {{value}} </body> </html> 在这段代码中,我们是用value方法定义了一个服务,服务名称为HQValue,值为:10,这是一个很简单的例子。 constant(name, value) constant(name, value)也可以注册一个服务,值可以是一个字符串、数字、数组、对象或函数,和value(name, object)很像有木有。对上面的示例进行简单的修改: <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title>AngularJS</title> <script type="text/javascript" src="js/angular.min.js"></script> <script type="text/javascript"> angular.module("myApp", []) .constant("HQConstant", 10) .config(function(HQConstant) { console.info(HQConstant); }) .controller("myCtrl", function($scope, HQConstant) { $scope.value = HQConstant; }); </script> </head> <body ng-app="myApp" ng-controller="myCtrl"> {{value}} </body> </html> 细心的小伙伴应该可以发现constant(name, value)和value(name, object)的用法虽然很想,但是二者也是有区别的,不然也就没必要搞两个出来了,二者最大的区别在于使用constant(name, value)注册的服务可以在config(configFn)方法中注入,而value(name, object)不可以。通常用value(name, object)来注册服务对象或者函数,而用constant(name, value)来配置数据。 service(name, constructor) 使用service(name, constructor)注册服务,服务对象是使用new进行实例化的,所以我们应该给this添加属性。 <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title></title> <script src="js/angular.min.js"></script> <script type="text/javascript"> angular.module("myApp", []) .service('HQString', function() { this.toUpperCase = function(x) { return x.toUpperCase(); } }).controller("myCtrl", function($scope, HQString) { $scope.name = HQString.toUpperCase('jianggujin'); }); </script> </head> <body ng-app="myApp" ng-controller="myCtrl"> <div>{{name}}</div> </body> </html> 在这段代码中,我们使用了service(name, constructor)注册了一个服务,服务名为HQString,我们为该服务添加了一个toUpperCase用于将字符串转换为大写。 factory(name, providerFunction) 使用factory(name, providerFunction)注册服务其实就是创建一个对象作为providerFunction的返回值,注入到controller中的其实就是创建的对象。我们使用factory(name, providerFunction)来实现service(name, constructor)同样的功能,代码如下: <head> <meta charset="UTF-8"> <title></title> <script src="js/angular.min.js"></script> <script type="text/javascript"> angular.module("myApp", []) .factory('HQString', function() { return { toUpperCase: function(x) { return x.toUpperCase(); } }; }).controller("myCtrl", function($scope, HQString) { $scope.name = HQString.toUpperCase('jianggujin'); }); </script> </head> <body ng-app="myApp" ng-controller="myCtrl"> <div>{{name}}</div> </body> provider(name, provider) provider(name, provider)是可以传入config(configFn)的服务,如果我们想要在 service对象启用之前,先进行模块范围的配置,那就应该用 provider。使用provider(name, provider)注册服务,我们需要为this添加$get函数,函数返回用于注入到controller中对象,我们也可以为this添加其他属性以便于我们在config(configFn)方法中使用。需要注意的是,如果我们的服务名称为:HQString,那么我们在config(configFn)方法中注入的名称应该为:HQStringProvider。下面我们通过代码来看一下如何使用: <head> <meta charset="UTF-8"> <title></title> <script src="js/angular.min.js"></script> <script type="text/javascript"> angular.module("myApp", []) .provider('HQString', function() { this.defaults = "defaults"; this.$get = function() { return { toUpperCase: function(x) { return x.toUpperCase(); } }; } }).config(function(HQStringProvider) { console.info(HQStringProvider.defaults) }).controller("myCtrl", function($scope, HQString) { $scope.name = HQString.toUpperCase('jianggujin'); }); </script> </head> <body ng-app="myApp" ng-controller="myCtrl"> <div>{{name}}</div> </body>
文章
JavaScript  ·  前端开发
2016-03-29
AngularJS1.3一些技巧
前言      框架选择。在上一篇文章评论中,有人说angular1.3是个过时的东西,建议使用angular2。其实这种说法很像拿jQuery1.x和jQuery2.x做比较,新的版本当然会有优化优势的地方,但并不一定是最适合你项目的。当你项目必须支持IE6/7/8时,那又得使用jQuery1.x版本。所以不要以新不新去选择一个框架或者某个版本,而是看是不是适合的。当初用angular1.3是他比较成熟有配套的文档,而angular2的文档是不健全的,另外有一点是1.x与2.x的区别太大了,两者的用法没有继承性。更重要的是,目前的angular2只有Alpha版本(测试),并没有一个正式版本。      性能。有人说angular2的性能会比较好,我还没有用过,不做什么评论。但对于angular1.x,我确实是不放心它的性能的,作为PC Web我敢用angular,但在移动终端我不敢用,在我看来无论从框架体积或框架运行效率,在脆弱的移动端都是致命的。有一些基于angular做的Hybrid框架(例Ionic),希望使用过的人能告诉我它体验怎么样(性能上)。   一些技巧      这篇文章记录一些angular1.3的小技巧,angular2我会找个时间做个实践。 1. ng-repeat多个字段排序的写法 使用orderBy过滤器,第一个参数是一个数组,表示依次按数组中的属性值进行排序(若按第一项比较的值相等,再按第二项比较),第二个参数是正序还是倒序(默认是正序)。 ng-repeat="groupUser in groupUsers | orderBy:['isOwner','isAdmin']:true"   2. ng-include引入HTML片段 使用ng-include,第一个参数是页面的相对地址的字符串。应该注意,是一个字符串,不是ng-expression,所以不要忘了加单引号,否则会发现怎么都引不进这个HTML片段。 <div ng-include="'msgs.html'"></div>   3. ng-bind的$scope对象没有随着数据变化而变化 自己实现的ajax,获取数据后,设置到$scope上,view却没有更新。这其实就是angular双向数据的原因,angular不可预见的scope变化,是不会帮忙刷新view的(例$.ajax或setTimeout)。解决方法就是,数据设置到$scope上后,手动调$scope.$apply();。 PS:一些指令(例ng-click、ng-model)以及服务(例$timeout、$http)才会自动刷新view。   4. 移动触摸(Touch)事件 angular-touch模块提供了触摸的事件和其他手势ngSwipeLeft、ngSwipeRight。   5. ng-bind-html的内容无法正常的显示在页面中 使用ng-bind-html属性,该属性依赖于$sanitize,也就是需要引入angular-sanitize.js文件。但会发现ng-bind-html的内容无法正常的显示在页面中,这是因为某些标签会被angularJS认为是不安全的自动过滤掉,而为了保留这些表情就需要开启非安全模式。 <div ng-bind-html="article.content | trustHtml"> </div>   myApp.filter('trustHtml', function ($sce) { return function (input) { return $sce.trustAsHtml(input); } }); 其中$sce是angular自带的安全处理服务,$sce.trustAsHtml(input) 返回的是受信任的对象。   6.  如何划分一个module 我的想法是在关系比较密切(业务逻辑)的页面可以划为一个module,因为页面可能存在共用service或template或directive(controller不共用),而这些元件归属于同个module,我们就可以不同页面调用了。而不想关的页面可划分为另一个module,增加代码的清晰度。   7. 是否要把工具类弄成service 在弄工程之前,我会考虑到是否要将一些工具类封装成一个service(为了看起来代码统一),但我发觉是没有必要的,因为service是归属于某个模块的,而我们的工具类可能在不同模块都有使用,不归属于某个模块。把工具类当成一个jquery的库引入即可。   8. 配合RequireJS使用 angular没有异步加载模块的功能,所以使用配合RequireJS使用的效果还是不错的。在这里面有些异议的是对于模块定义的地方,是该把一个模块定义成RequireJS的模块还是angular的服务(可以依赖注入),我觉得还是功能归属的问题,如果是全局使用的工具服务,就定义成RequireJS模块,而如果是与模块密切相关的业务逻辑就使用服务。 PS:可在RequireJS的config加上urlArgs,可以避免缓存问题。 urlArgs: "bust=" + (new Date()).getTime() //可用来清理缓存,在部署到生产环境去掉。   9. iframe打开跨域URL时报错 <iframe width="100%" height="100%" ng-src="{{url}}"></iframe> 如果不做处理,上面的跨域URL是打不开的, 需要定义白名单。 myApp.config(function($sceDelegateProvider) { $sceDelegateProvider.resourceUrlWhitelist([ // Allow same origin resource loads. 'self', // Allow loading from our assets domain. Notice the difference between * and **. "https://link.bingosoft.net/**"]); });   10. 使用其他Controller的scope的属性方法 先声明我并不清楚我的用法是否恰当。使用其他Controller的scope局限于其parent scope,而不是任何Controller的都可以访问。scope有个属性$parent, 通过这个属性可以找到某一层Controller的scope。 var parentScope = $scope.$parent.$parent.$parent; PS:多少层$parent是我打印scope对象出来找的。   11. form表单的自动提交功能 在输入框点击回车时候,AngularJS会默认触发第一个button的click事件。   总结 这一篇是angular1.3的小技巧,希望有用。   本文为原创文章,转载请保留原出处,方便溯源,如有错误地方,谢谢指正。 本文转自 海角在眼前 博客园博客,原文链接:http://www.cnblogs.com/lovesong/p/4889931.html   ,如需转载请自行联系原作者
文章
安全  ·  缓存  ·  前端开发  ·  JavaScript
2017-11-12
AngularJS 服务 demo
我们知道Angular提供的标准服务组件有以下: $http:用于处理 XMLHttpRequest $location:提供当前URL的信息 $q: 异步请求使用,promise/deferred模块 $routeProvider:配置路由 $log:日志服务 $http有下面短方法:$http.get() $http.head() $http.post() $http.put() $http.delete() $http.jsonp()   $的命名约定 前缀$是表示 Angular自己提供的服务名称,如$scope或$provide等,为了防止冲突,最好避免命名自己开发的服务以为$开头。 如果你检查一个scope内部,你也可能会发现一些属性开头也是以 $开头。这些特性被认为是私有的,并且不应该访问或修改。 下面这个代码是将$window注入到自己的服务中: Java代码   angular.module('myModule', [], function($provide) {     $provide.factory('notify', ['$window', function(win) {       var msgs = [];       return function(msg) {         msgs.push(msg);         if (msgs.length == 3) {           win.alert(msgs.join("\n"));           msgs = [];         }       };     }]);   });   这是一个通知服务,将消息发送到所有Angular提供的window窗口中显示。 要注意的是所有AngularJS服务都是单例的。这意味着在每一个注入器中都只有一个需要的服务的实例。因为AngularJS极度讨厌全局的东西,这是符合面向对象OO。   $resource服务与REST 在我们看怎样用 ngResource 方法创建一个 resource 资源之前,我们先看一下怎样用基本的$http 服务做类似的事情.比如我们的信用卡 resource,我们想能够读取、查询、保存信用卡信息,另外还要能为信用卡还款.这儿是上述需求一个可能的实现: Java代码   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}});           }       };    }]);   $resource是一个依赖$Http的服务组件,它创建了一个资源对象,让你与RESTful服务器端数据源实现交互的工厂。返回的是资源对象,提供了高层次的行为,而不需要与低级别$ HTTP服务交互操作方法。需要ngResource 安装(<script src="lib/angular/angular-resource.js"></script>)。 对返回的数据进行默认的如下操作: Java代码   {    'get': {method:'GET'},   'save': {method:'POST'},   'query': {method:'GET', isArray:true},   'remove': {method:'DELETE'},   'delete': {method:'DELETE'}    };   例如: Java代码   var User = $resource('/user/:userId', {userId:'@id'});   var user = User.get({userId:123}, function() {   user.abc = true;   user.$save();    });   User定义为资源$resource类型,小写的user是其一个实例,实际是从服务器抓取的根据id为123的一个User Json数组,那么我们下面可以对user这个实例使用上面几个默认操作,比如user.$save();。可以轻松地执行CRUD操作(创建,读取,更 新,删除)。 总结为:  修改 Java代码   app.factory('itemCategoryService', ['$resource', function($resource) {     return $resource(       '../systemConfig/updateCategory/:id', {}, {edit: {method: 'put'}}     );   }]);   var item = new itemCategoryService;   item.name = $scope.typeData.name;   item.code = $scope.typeData.code;   item.$edit({'id': $scope.typeData.id}, function(data) {     $location.url('/typeList');   }, function(error) {   });   删除 Java代码   $resource('../systemConfig/delCategory/:id').remove({'id' : id});     下面以phone举例返回列表: Java代码   var phonecatServices = angular.module('phonecatServices', ['ngResource']);       phonecatServices.factory('Phone', ['$resource',     function($resource){       return $resource('phones/:phoneId.json', {}, {         query: {method:'GET', params:{phoneId:'phones'}, isArray:true}       });     }]);   这是从后台返回phone列表的$resource用法。节省了$http之类转换。   AngularJS提供了一个内置Service $q,它提供了一种承诺/延后(promise/deferred),可以保证我们的调用代码一定能够拿到数据。当然,我们可以猜到,最后去服务器取数据 的方式肯定是异步的。只不过这个服务提供了表面上是同步访问的API,当数据获取成功之后,自动将数据提供给调用的代码。 1. 创建一个Service,去服务器读取数据: Java代码   // $q 是内置服务,所以可以直接使用   ngApp.factory('UserInfo', ['$http', '$q', function ($http, $q) {     return {       query : function() {         var deferred = $q.defer(); // 声明延后执行,表示要去监控后面的执行         $http({method: 'GET', url: 'scripts/mine.json'}).         success(function(data, status, headers, config) {           deferred.resolve(data);  // 声明执行成功,即http请求数据成功,可以返回数据了         }).         error(function(data, status, headers, config) {           deferred.reject(data);   // 声明执行失败,即服务器返回错误         });         return deferred.promise;   // 返回承诺,这里并不是最终数据,而是访问最终数据的API       } // end query     };   }]);    2. 在Controller上(以同步方式)使用这个Service:赋值 Java代码   angular.module('ngApp')     .controller('MainCtrl', ['$scope', 'UserInfo', function ($scope, UserInfo) { // 引用我们定义的UserInfo服务       var promise = UserInfo.query(); // 同步调用,获得承诺接口       promise.then(function(data) {  // 调用承诺API获取数据 .resolve           $scope.user = data;       }, function(data) {  // 处理错误 .reject           $scope.user = {error: '用户不存在!'};       });     }]);    欢迎讨论和交流AngularJS及前端开发
文章
前端开发  ·  Java  ·  API  ·  监控  ·  网络架构  ·  数据格式  ·  JSON
2016-05-12
AngularJS1.3一些技巧
前言      框架选择。在上一篇文章评论中,有人说angular1.3是个过时的东西,建议使用angular2。其实这种说法很像拿jQuery1.x和jQuery2.x做比较,新的版本当然会有优化优势的地方,但并不一定是最适合你项目的。当你项目必须支持IE6/7/8时,那又得使用jQuery1.x版本。所以不要以新不新去选择一个框架或者某个版本,而是看是不是适合的。当初用angular1.3是他比较成熟有配套的文档,而angular2的文档是不健全的,另外有一点是1.x与2.x的区别太大了,两者的用法没有继承性。更重要的是,目前的angular2只有Alpha版本(测试),并没有一个正式版本。      性能。有人说angular2的性能会比较好,我还没有用过,不做什么评论。但对于angular1.x,我确实是不放心它的性能的,作为PC Web我敢用angular,但在移动终端我不敢用,在我看来无论从框架体积或框架运行效率,在脆弱的移动端都是致命的。有一些基于angular做的Hybrid框架(例Ionic),希望使用过的人能告诉我它体验怎么样(性能上)。   一些技巧      这篇文章记录一些angular1.3的小技巧,angular2我会找个时间做个实践。 1. ng-repeat多个字段排序的写法 使用orderBy过滤器,第一个参数是一个数组,表示依次按数组中的属性值进行排序(若按第一项比较的值相等,再按第二项比较),第二个参数是正序还是倒序(默认是正序)。 ng-repeat="groupUser in groupUsers | orderBy:['isOwner','isAdmin']:true"   2. ng-include引入HTML片段 使用ng-include,第一个参数是页面的相对地址的字符串。应该注意,是一个字符串,不是ng-expression,所以不要忘了加单引号,否则会发现怎么都引不进这个HTML片段。 <div ng-include="'msgs.html'"></div>   3. ng-bind的$scope对象没有随着数据变化而变化 自己实现的ajax,获取数据后,设置到$scope上,view却没有更新。这其实就是angular双向数据的原因,angular不可预见的scope变化,是不会帮忙刷新view的(例$.ajax或setTimeout)。解决方法就是,数据设置到$scope上后,手动调$scope.$apply();。 PS:一些指令(例ng-click、ng-model)以及服务(例$timeout、$http)才会自动刷新view。   4. 移动触摸(Touch)事件 angular-touch模块提供了触摸的事件和其他手势ngSwipeLeft、ngSwipeRight。   5. ng-bind-html的内容无法正常的显示在页面中 使用ng-bind-html属性,该属性依赖于$sanitize,也就是需要引入angular-sanitize.js文件。但会发现ng-bind-html的内容无法正常的显示在页面中,这是因为某些标签会被angularJS认为是不安全的自动过滤掉,而为了保留这些表情就需要开启非安全模式。 <div ng-bind-html="article.content | trustHtml"> </div>   myApp.filter('trustHtml', function ($sce) { return function (input) { return $sce.trustAsHtml(input); } }); 其中$sce是angular自带的安全处理服务,$sce.trustAsHtml(input) 返回的是受信任的对象。   6.  如何划分一个module 我的想法是在关系比较密切(业务逻辑)的页面可以划为一个module,因为页面可能存在共用service或template或directive(controller不共用),而这些元件归属于同个module,我们就可以不同页面调用了。而不想关的页面可划分为另一个module,增加代码的清晰度。   7. 是否要把工具类弄成service 在弄工程之前,我会考虑到是否要将一些工具类封装成一个service(为了看起来代码统一),但我发觉是没有必要的,因为service是归属于某个模块的,而我们的工具类可能在不同模块都有使用,不归属于某个模块。把工具类当成一个jquery的库引入即可。   8. 配合RequireJS使用 angular没有异步加载模块的功能,所以使用配合RequireJS使用的效果还是不错的。在这里面有些异议的是对于模块定义的地方,是该把一个模块定义成RequireJS的模块还是angular的服务(可以依赖注入),我觉得还是功能归属的问题,如果是全局使用的工具服务,就定义成RequireJS模块,而如果是与模块密切相关的业务逻辑就使用服务。 PS:可在RequireJS的config加上urlArgs,可以避免缓存问题。 urlArgs: "bust=" + (new Date()).getTime() //可用来清理缓存,在部署到生产环境去掉。   9. iframe打开跨域URL时报错 <iframe width="100%" height="100%" ng-src="{{url}}"></iframe> 如果不做处理,上面的跨域URL是打不开的, 需要定义白名单。 myApp.config(function($sceDelegateProvider) { $sceDelegateProvider.resourceUrlWhitelist([ // Allow same origin resource loads. 'self', // Allow loading from our assets domain. Notice the difference between * and **. "https://link.bingosoft.net/**"]); });   10. 使用其他Controller的scope的属性方法 先声明我并不清楚我的用法是否恰当。使用其他Controller的scope局限于其parent scope,而不是任何Controller的都可以访问。scope有个属性$parent, 通过这个属性可以找到某一层Controller的scope。 var parentScope = $scope.$parent.$parent.$parent; PS:多少层$parent是我打印scope对象出来找的。   总结 这一篇是angular1.3的小技巧,希望有用。   本文为原创文章,转载请保留原出处,方便溯源,如有错误地方,谢谢指正。 本文地址 :http://www.cnblogs.com/lovesong/p/4889931.html 转载:http://www.cnblogs.com/lovesong/p/4889931.html
文章
缓存  ·  安全  ·  前端开发  ·  JavaScript
2016-05-20
Ballerina 面向全栈开发人员:创建后端 API 的指南
背景一个最简单的 Web 应用程序由 3 层构成,即客户端(前端)、服务器端(后端)和持久层(数据库)。全栈开发指的是针对 Web 应用程序的全部 3 层的实践。前端开发涉及 HTML、CSS 和原生 JavaScript, 或者一到多个 JavaScript 框架/库(如 JQuery 或 React.js)。在过去几年中,可用的工具、框架和库呈指数级增长,因此,前端开发本身就是一个非常广泛的课题。后端开发通常涉及服务器端脚本语言(如 PHP 或 JSP)又或者前端使用的服务。随着单页Web 应用程序 (SPA) 的出现,开发人员已经摆脱了传统的服务器端脚本语言,转而采用 API(REST、GraphQL、WebSocket 等)作为后端。持久层包括一个或多个 SQL 或者 NoSQL 数据库。但随着“大数据”的出现,数据存储不再局限于传统的数据存储。热门的栈MERN 栈- 图片来源在上面提到的每一层使用的所有技术中,有一些技术比其他技术更受欢迎。当这些覆盖所有三层的技术结合在一起时,我们称之为“栈”,近些年来,我们已经看到了几个流行的栈。LAMP / LEMP — JavaScript 用于前端。Linux 用于托管服务,Apache/Nginx 作为 Web 服务器,MySQL 作为持久层,PHP 作为后端(或服务器端)语言。像 Laravel 和 Symphony 这样的框架在这个栈下很流行。MEAN — MongoDB 用于数据持久层,Express 作为后端框架,AngularJS 作为前端 JavaScript 框架,NodeJS 作为服务器运行时。MERN — 与 MEAN 栈相同,只是选择了 ReactJS 而不是 Angular。Ruby on Rails — 用 Ruby 编写的 Web 应用程序框架。Django — JavaScript 用于前端,Python Django 框架用于后端,以及相应的 SQL 或 NoSQL 数据库层。然而,栈不再那么简单了。对于给定的一层,可用的替代技术成倍增加,在给定的层中,我们可以用来组合开发最终产品的不同技术的数量也在成倍增加。现代全栈开发在全栈开发方面,SPA(单页应用程序)和 PWA(渐进式 Web 应用程序)正在成为规范,并且出现了 SSR(服务器端渲染)等概念来解决它们的局限性。这些 Web 应用程序(前端)应该与后端 API(REST、GraphQL 等)一起工作,以便为终端用户提供最终功能。随之出现了诸如 BFF(服务于前端的后端)之类的概念,以使后端 API 与前端用户体验 (UX) 保持一致。BFF — 服务于前端的后端一个组织可以有多个微服务,这些服务被不同的使用方使用,如移动应用程序、Web 应用程序、其他服务/API 和外部使用方。然而,现代 Web 应用程序需要一个紧密耦合的 API 来与前端 UX 紧密配合, 因此,BFF 充当了前端和微服务之间的接口。一个 BFF 调用多个下游服务在前端构造一个视图。下游 API 可以是不同的类型(REST、GraphQL gRPC 等)。阅读模式:服务于前端的后端来深入了解 BFF 架构模式。记住上面的概念,让我们进一步讨论一下现代 Web 开发。全栈开发背景下的后端开发开发后端 API 可能意味着两件事:开发 BFF — 充当前端 UX 和后端微服务之间的适配器。开发微服务 — 开发前端直接或间接(通过 BFF)使用的单个微服务。在全栈开发的背景下,我们只需考虑由前端直接调用的后端 API。这些 API 可以编写为 BFF API 或单独的微服务。选择栈如今,开发人员不会因为一个栈很流行就去使用它,他们选择最合适的前端技术来匹配他们希望实现的 UI/UX。然后他们选择后端技术时会考虑几个因素,包括其上市时间、可维护性和开发人员的经验。在这篇文章中,我将介绍一个新的并且很有前景的后端开发候选技术,Ballerina。在将来,当你在为全栈开发做技术选型时,可以考虑一下它。什么是 Ballerina?Ballerina 编程语言徽标Ballerina 是一种开源的云原生编程语言,旨在简化网络服务的使用、组合和创建。Ballerina Swan Lake 是 Ballerina 语言于今年发布的下一个主要版本,它在所有方面都进行了重大改进,包括改进的类型系统、增强的类 SQL 语言集成查询、增强/直观的服务声明等等。Ballerina 背后的主要动机是让开发人员能够专注于业务逻辑,同时减少集成云原生技术所需的时间。使用 Ballerina 的内置网络原语直接在云上定义和运行服务的方式在这场变革中发挥了关键作用。灵活的类型系统、面向数据的语言集成查询、增强和直观的并发处理以及内置的可观察性和跟踪支持,使 Ballerina 成为云时代的首选语言之一。在开发前端直接调用的 API 时,我们有几个常用的选择:REST APIGraphQL APIWebSocket API 一旦选择了合适的 API 类型,接下来我们必须考虑以下因素:安全通信验证授权监控、可观测性和日志记录除了上述因素外,我们在开发 API 时还必须考虑可维护性和开发者体验。让我们看看 Ballerina 如何为开发上述 API 类型提供支持,以及是什么让 Ballerina 成为后端 API 开发领域中一个有前景的候选者。Ballerina 与网络交互Ballerina 编程语言的主要目标之一是简化网络交互代码的编写。考虑到这一点,Ballerina 在语言中内置了网络原语。当其他主流编程语言都将网络视为另一种 I/O 资源时,Ballerina 为网络交互提供了更为优秀的支持。为了实现这一目标,Ballerina 采用了以下优秀的组件设计:侦听器 — 充当网络层和服务层之间的接口。侦听器代表底层传输,如 HTTP、gRPC、TCP 或 WebSocket。服务—表示向最终用户公开组织功能的服务。HTTP、GraphQL、gRPC 和 WebSocket 是此类服务的一些例子。资源方法— 表示服务中的一个功能单元。例如,如果我们考虑使用一个简单的 CRUD 服务来管理库存,添加库存由一个单独的资源方法表示,而删除库存操作则由另一个资源方法表示。客户端—如今编写服务通常包括调用一个或多个外部或内部服务。例如:在你的一项服务中,你可能想要发送一封电子邮件。为此,你需要一个电子邮件客户端。2. 同一个服务可能需要调用一个或多个内部 gRPC 服务。为此,你需要 gRPC 客户端。同样,编写服务需要调用外部服务。为此,Ballerina 有一个丰富的概念,称为客户端,外部调用由远程方法表示。在 Ballerina 运行时中调用远程方法是异步的(非阻塞,同时不需要显式回调或侦听器)。这些语言内置的网络原语与其他语言特性(如显式错误处理、内置 json/xml 支持和灵活的类型)相结合,可帮助开发人员更快地编写直观且可维护的网络交互,这反过来又使开发人员和组织能够更多地关注创新。Ballerina 特性一览图让我们探索一下如何使用 Ballerina 对 REST 和 GraphQL API 的支持来编写直观且有意义的后端 API。请按照入门指南安装和设置 Ballerina。设置 Ballerina开发 REST API让我们看看如何使用 Ballerina 编写 REST API。说 "Hello World!"用 Ballerina 编写的 hello world REST API 如下所示:让我们在这里解码语法的每个部分:import ballerina/http;- 导入 ballerina/http 包。service / on new http:Listener(8080)- 在 HTTP 侦听器上创建一个上下文路径为“/”的服务,该侦听器侦听 8080 端口,服务的类型由附加的侦听器的类型决定。在当前实例中,由于我们的侦听器是 HTTP 类型的,所以它就是一个 HTTP 服务。resource function get greeting() returns string- 表示可以通过此 HTTP 服务执行单个操作。“get”是“资源访问器”。简单来说,它代表 HTTP 方法(get、post、delete 等)。“greeting”是函数名,函数名作为路径,这意味着资源路径“/greeting”由该资源方法处理。“returns string”表示此服务返回一个字符串,我们也可以在这里返回复杂的对象。return "Hello World!";- 表示资源方法的返回值。这里是字符串“Hello World”。下图显示了 Ballerina HTTP 服务语法的概述:Ballerina HTTP 服务结构(来源)要深入了解 Ballerina HTTP 服务语法,尤其是如何使用查询和路径参数、payload 数据绑定等,请参考以下文章:HTTP Deep-Dive with Ballerina: Services集成示例 — 货币转换 API以下是一个稍微复杂一点的 REST API。给定基准货币、目标货币和金额,此 API 将返回转换后的金额。此 API 使用外部服务来获取最新汇率。与 hello world 示例相比,这个示例展示了 Ballerina 一些更有趣的功能。service / on new http:Listener(port) - 基础路径现在是 /,端口是可配置的,这意味着它可以在运行时进行配置,正如 configurable int port = 8080 中所定义的,端口的默认值为 8080,并且是可配置的,可配置变量也是一个值得注意的特性。resource function get convert/[string baseCurrency]/to/string targetCurrency returns decimal|error - 在这种情况下,资源路径是 /convert/{baseCurrency}/to/{targetCurrency} 并且现在需要一个名为 amount 的查询参数。此资源方法会返回一个十进制值(转换速率)或一个错误(映射到 500 - 内部服务器错误)。ConversionResponse response = check dccClient->get(string /latest?base=${baseCurrency}) - 调用外部汇率 API,并将响应转换为公开的记录 ConversionResponse。此调用是非阻塞的。响应有效载荷被无缝地转换为了一个公开的记录,这体现了 Ballerina 的默认开放原则。运行后,如下所示的 curl 请求会将 100 美元转换为英镑。红利:低代码开发Ballerina 具有无泄漏的图形表示。也就是说,您可以同时编辑源代码和低代码视图(图形表示)。下图是上述 API 的低代码视图:上述货币转换 API 的低代码视图尽管我们不会在 Ballerina 的低代码方向做过多探索,但它对于非技术或技术水平较低的人来说,这有助于他们理解和编写代码,所以也试一试吧。无泄漏 — 任何东西都可以用代码编程,代码中的一切都是可视的。一个简单的 CRUD 服务下面是一个用 Ballerina 编写的 CRUD 服务示例,它操作一组保存在内存中的产品。大部分语法是不言自明的,该服务有 4 种资源方法:列出所有产品 — GET /products添加新产品 — POST /products更新产品 — PUT /product删除产品 — DELETE /products/{id}请注意如何定义类型来表示产品、价格和货币。然后,我们在需要实现所需模式的地方定义了响应类型,ProductCreated 表示添加产品的响应,ValidationError 表示验证中的错误。拥有这样的模式有助于开发人员轻松理解代码。只需查看资源方法定义,开发人员就可以清楚地了解资源方法。什么是资源路径,需要什么查询/路径参数,有效负载是什么,以及可能的返回类型是什么。这是一个 POST 请求,发送到 /products(通过查看资源方法派生),需要 Product 类型的有效负载,并返回验证错误 (400) 或带有位置标头的 HTTP CREATED 响应 (201)。生成 OpenAPI 规范一旦我们用 Ballerina 编写了服务,只需指向源文件即可生成 OpenAPI 规范。通过查看源代码,它将输出带有相应状态代码和模式的 OpenAPI 规范。您可以在 OpenAPI 部分阅读更多内容:Ballerina OpenAPI 工具生成完整的 OpenAPI 规范可帮助您生成所需的客户端。在我们的例子中,生成 JavaScript 客户端并将我们的前端与后端轻松集成。保护服务您可以通过将 HTTP 侦听器更新为 HTTPS 侦听器来保护您的服务,如下所示。您也可以启用双向 SSL 并进行高级配置。更多信息请参阅有关 HTTP 服务安全性的 Ballerina 示例。验证Ballerina 内置了对 3 种身份验证机制的支持。JWT您可以提供证书文件或授权服务器的 JWK 端点 URL 并启用 JWT 签名验证。例如,如果我们要使用像 Asgardeo 这样的 IDaaS(身份即服务)来保护我们的服务,我们只需在服务中添加以下注解:此外,您可以保护整个服务或仅保护资源路径的子集。您可以在 JWT 中验证颁发者或受众。您可以根据声明执行授权(稍后解释)。请参阅 Ballerina 示例中的 REST API 安全部分以了解更多信息。OAuth2与 JWT 类似,您可以使用 OAuth2 保护您的服务。有关更多详细信息,请参阅服务 - OAuth2 示例。基本认证对于基本身份验证,有 2 个用户存储选项可用;文件和 LDAP。请参考以下示例以了解它是如何完成的:带有文件用户存储的基本身份验证使用 LDAP 用户存储的基本身份验证Authorization使用 OAuth2 和 JWT,您可以验证每个服务或每个资源的作用域。在这两种情况下,您都可以指定自定义范围键,默认值为 scope。对于 JWT,您可以使用包含用户角色(基于角色的访问控制 — RBAC)或权限(细粒度访问控制)的自定义声明来授权单个操作。如上所示,/products 服务验证传入的 JWT 是否具有列出产品的 product:view 权限和创建产品的 product:create 权限。scopeKey 设置为 permissions,这是要在 JWT 中进行验证的声明的名称。此外,它还验证了发行者和受众。客户端显然,在编写后端 API 时,您必须与外部服务进行通信,至少你需要一个数据库客户端,无论是 DB 客户端、HTTP 客户端还是 gRPC 客户端,Ballerina 都能很好地满足您的需求。最重要的是,Ballerina 中的客户端调用是非阻塞的,开发人员无需添加任何回调或侦听器。看看 Ballerina 的客户端有多方便:基础 REST 客户端示例具有承载令牌身份验证的 REST 客户端具有 OAuth2 客户端凭据授予类型的客户端具有 OAuth2 JWT 不记名授权类型的客户端此外,Ballerina 对弹性有丰富的支持,请参阅以下示例以了解它们:断路器负载均衡器故障转移重试GraphQL APIs为了使这篇文章简短,我不会深入讨论如何编写 GraphQL API,但是,与 REST API 类似,Ballerina 对 GraphQL 服务具有相同级别的支持。请参阅以下链接以了解更多信息:一个简单的 GraphQL 示例GraphQL 中的分层资源路径GraphQL 的 JWT 身份验证请参阅 Ballerina 网站的参考示例部分,以了解更多关于编写 GraphQL 服务的信息。WebSocket APIs我也不会深入讨论这个问题。有关编写 WebSocket 服务的更多详细信息,请参阅 Ballerina 网站的示例参考部分下的 WebSockets 和 WebSocket 安全部分。可观察性可观察性是该语言内置的关键特性之一。使用 Ballerina,您可以开箱即用地执行分布式跟踪和指标监控。追踪分布式追踪可通过 Jaeger 和 Choreo 实现。为了将追踪发布到 Jaeger(或 Choreo),您只需在代码中添加一行导入。在运行时,您的服务将使用 Open Telemetry 标准将追踪发布到 Jaeger(或 Choreo)。使用 Jaeger 和 Ballerina 进行分布式跟踪日志记录Ballerina 提供的日志框架非常适合使用 logstash 和类似的日志分析器进行日志分析。在编写代码时,您可以将额外的键值对传递到日志行。上述日志行的输出如下所示:指标可以使用 Prometheus 和 grafana 监控实时指标。此外,还可以使用 Choreo 监控实时指标..Choreo 中的可观察性视图(来源)与分布式跟踪类似,只需向源代码中添加一行导入,并导入一个现成的 grafana 仪表板,即可发布和监控实时指标。Ballerina 的实时指标 Grafana 仪表板从以下链接阅读有关 Ballerina 可观察性功能的更多信息:Prometheus、Grafana 和 Jaeger 的可观察性Choreo 的可观察性持久层后端开发的下一个主要方面是持久层。Ballerina 拥有丰富的 SQL 和 NoSQL DB 客户端。通过客户端进行的 DB 调用在 Ballerina 中是非阻塞的SQL截至到目前,以下客户端是可用的:MySQLMSSQLOraclePostgreSQL此外,Ballerina 还提供了一种非常方便的方式,可以使用 RawTemplates 编写预先准备好的语句。在上面的示例中,${} 表示绑定到查询的变量,上面的代码在运行时作为准备好的语句执行。Data Binding and Streams类似地,我们可以使用如下的选择查询将数据作为用户定义类型的流来获取。假设我们有如下的产品记录:产品表定义如下:您可以将数据作为产品记录流获取,如下所示:请注意,记录字段名称和提取的列名称是相似的。NoSQLMongoDBCosmosDBAWS DynamoDBRedis除了 NoSQL 的常见优势之外,Ballerina 内置的 JSON 和开放记录类型在处理非结构化或半结构化数据时会派上用场。注意:Ballerina 的生态系统仍在完善过程中。因此,还没有功能齐全的 ORM 可用。其它值得注意的功能内置 JSON/XML 支持正如我们已经看到的,Ballerina 内置了对主流传输格式 JSON 和 XML 的支持。使用 Ballerina,您可以在用户定义的类型和 JSON 之间无缝转换,正如我们在 HTTP 服务和 DB 示例中看到的那样。结构类型系统Ballerina 不使用名义类型(如 Java/Kotlin),而是依赖结构类型(如 Go/TypeScript)来确定子类型。这允许开发人员在用户定义的类型之间以及在用户定义的类型和 JSON 之间无缝转换。静态类型Ballerina 是静态类型的。这使得 Ballerina 能够提供一组丰富的工具来编写可靠且可维护的代码。同时,Ballerina 遵循“默认开放”的原则,您只需定义您感兴趣的内容,开放记录就是这种用法的一个例子。显式错误处理应显式处理错误。正如我们在示例中看到的,客户端调用返回结果和错误的并集。开发人员应该键入 check 检查错误,并显式地处理它们。空安全Ballerina 是空安全的。可维护结合以上所有方面,Ballerina 成为一种可维护且可靠的网络编程语言。图形化正如我们简要看到的,Ballerina 有一个非常好的、无泄漏的低代码特性。Ballerina 使用序列图来可视化网络交互,这对于技术水平较低和非技术人员编写程序和理解程序非常有用。总结在本文中,我想简单而全面地概述一下 Ballerina 编程语言对编写后端 API 的支持。我们介绍了如何深入编写 REST API,我们还研究了如何保护服务、如何执行身份验证和授权以及生成 OpenAPI 规范。接下来,我们简要介绍了如何编写 GraphQL 和 WebSocket 服务,然后我们研究了可观察性特性和持久性层支持(针对 SQL 和 NoSQL 数据库),最后,我们看了一些值得注意的 Ballerina 特性。我认为所讨论的内容将有助于您更多地探索 Ballerina 编程语言,并了解它在后端 API 开发环境中的重要性。我希望我能够确定 Ballerina 是一种真正的云原生编程语言,它将网络原语视为一等公民。我邀请你进一步探索 Ballerina 编程语言。感谢您关注本文,随时分享您的意见和建议。此外,如果您还有其他问题,请联系我或 Ballerina 社区。作者介绍:Imesha Sudasingha 是 WSO2 的高级软件工程师,他还是 Apache 软件基金会的成员,现任 Apache OODT 项目管理委员会主席,他一直是开源的持续贡献者和推动者,在多个领域拥有工作经验,包括企业集成、支付和 DevOps,他目前参与了 Ballerina 项目,通过 IDE 工具参与改善 Ballerina 用户的开发人员体验。原文链接:https://www.infoq.com/articles/ballerina-fullstack-rest-api了解更多软件开发与相关领域知识,点击访问 InfoQ 官网:https://www.infoq.cn/,获取更多精彩内容!
文章
SQL  ·  JSON  ·  前端开发  ·  NoSQL  ·  JavaScript  ·  API  ·  数据库  ·  网络架构  ·  数据格式  ·  微服务
2022-04-24
AngularJs $compile编译服务与指令
$compile 这是个编译服务。编译一段HTML字符串或者DOM的模板, 产生一个将scope和模板连接到一起的函数。 编译服务主要是为指令编译DOM元素,下面的一大段也是主要介绍指令的。 下面是一个被声明的带指令定义对象的指令的示例: var myModule = angular.module(...); myModule.directive('directiveName', [“injectables”,…,function factory(injectables,…) { var directiveDefinitionObject = {    priority: 0,    template: '<div></div>', // or // function(tElement, tAttrs) { ... },    // or    // templateUrl: 'directive.html', // or // function(tElement, tAttrs) { ... },    replace: false,    transclude: false,    restrict: 'A',    scope: false,    controller: function($scope, $element, $attrs, $transclude, otherInjectables) { ... },    controllerAs: 'stringAlias',    require: 'siblingDirectiveName', // or // ['^parentDirectiveName', '?optionalDirectiveName', '?^optionalParent'],    compile: function compile(tElement, tAttrs, transclude) {    return {       pre: function preLink(scope, iElement, iAttrs, controller) { ... },       post: function postLink(scope, iElement, iAttrs, controller) { ... }      }    // or    // return function postLink( ... ) { ... }    },    // or    // link: {      // pre: function preLink(scope, iElement, iAttrs, controller) { ... },      // post: function postLink(scope, iElement, iAttrs, controller) { ... }    // }    // or    // link: function postLink( ... ) { ... }    };    return directiveDefinitionObject; }); 这是一个完整的指令,所返回的对象的各项属性都写在上面了,下面对于指令对象属性的介绍,就不一一的写示例代码了,后面主要写下简单的就ok。 备注:任何为指定的参数都将设置为默认值。下面将会列出各默认值。 指令定义对象 指令定义的对象为编译器提供说明,其属性是: priority 当有一个DOM元素中定义了多个指令,有时有必要指定的指令的应用顺序。在编译函数被调用之前,先将其按优先级排序。这个属性的值越大,优先级越高,将会更先被编译。具有相同优先级的指令的顺序是未定义的。默认优先级为0。 如果该属性设置为true,那么当前指令的优先将会放在最后一组将执行(在当前优先级的任何指令将仍然作为未定义优先级的设置执行) scope 如果设置为false,则不会为指令创建任何scope。指令使用其父级scope。 如果设置为true,那么该指令将会创建一个新的子scope,这个scope继承父级的属性。如果在一个DOM的多个指令上定义新作用域,也只能创建一个新的作用域。模板有了新的作用域后,该作用域的规则不适用与模板所在的根节点。 如果设置为{},那么将会创建一个新的、隔离的作用域。该作用域不继承其父作用域,这样就不会在创建可重用的指令是影响到父作用域的数据。 这个隔离的作用域会有一组来自父作用域的数据组成的对象,该对象名称前缀为: @ or @attr : 结合局部作用域属性的DOM元素上的属性值。在DOM元素上和指令scope中以string类型绑定。如果没指定名称,那么与假定的指令作用域中的名称相同。 = or =attr:在指令作用域和父作用域之间设置数据的双向绑定。如果没指定名称,那么与假定的指令作用域中的名称相同。 & or &attr:提供了在父作用域的上下文中执行的表达式。 controller 该指令的控制器构造函数。控制器将会在预编译之前被实例化,并且可与其他指令共享(参见require属性)。这实现了指令之间的通信,增强了相互之间的行为。可写入以下参数: $scope:与元素相关联的当前作用域。 $element:当前元素。 $attr:当前元素上的属性。 $transclude:一个被预绑定到正确的嵌入范围的linking函数。该范围可以通过一个第一个可选的参数重写。function([scope], cloneLinkingFn). require 需要另外一个指令并将其控制器作为第四个参数注入linking函数。需要以指令的字符串名称(或字符串数组)注入。如果使用了数组,注入的参数将是一个数组中的相应的顺序。如果没有找到这样的指令,或如果该指令没有控制器,那么将会出现一个错误。该属性名称前缀为: 无前缀:定位当前元素所需的控制器。如果未找到错误,抛出一个错误。 ?:试图找到所需的控制器,如果没有找到,则通过空函数。 ^:通过搜索元素的父节点来寻找所需的控制器,如果没找到,抛出个错误。 ?^:通过搜索元素的父节点来寻找所需的控制器,如果没有找到,则通过空函数。 controllerAs 指令作用域内的控制器的别名。控制器的别名,以便在该指令模板中引用。该指令需要在适用范围内定义此配置。当指令被用作组件的情况下有用。 restrict EACM的子集,限制了对一个特定的指令声明式的指令。 E:元素名称,<my-directive></my-directive> A:元素属性,<div my-directive="exp"></div> C:元素类:<div class="my-directive: exp;"></div> M:注释,<!-- directive: my-directive exp --> template 将HTML的内容的指令块替换当前元素。过程将在新元素上更新之前旧元素的所有属性/类。该属性可以指定模板作为一个字符串或一个函数模板,采用两个参数tElement和tAttrs,并返回一个表示模板的字符串值。 templateUrl 与template基本相同,但模板通过指定的url加载。因为模板是异步加载的,所以conplie和link都会被赞同,等待模板加载完。 replace 指定要插入模块的位置,默认为false。 true:模板将会替换当前元素。 false:模板将会替换当前元素的内容。 transclude 编译元素的内容并且使其在指令内有效。这使得组件有私人的状态,并且嵌入的部分包含到父作用域。 true:该指令可嵌入内容。 false:嵌入整个单元包括在较低的优先级定义的任何指令。 compile function compile(tElement, tAttrs, transclude) { ... } compile函数分配模板的转换。由于大多数指令不做模板转换,所以它不经常使用。需要用到compile去转换模板的例子有ngRepeat,或者异步加载内容,如ngView。编译需要如下参数: tElement:模板元素,该指令已声明的元素。只有在元素和子元素上进行模板转换是安全的。 tAttr:模板属性,在所有的指令compile函数之间共享的属性。 transclude:一个transclude linking函数-- function(scope, cloneLinkingFn) 备注:如果模板被克隆,那么template实例和link实例是不同的对象。因此,所有在compile函数里克隆的DOM节点做DOM转换都是不安全的。具体来说,DOM监听应该在link函数里而不是在compile函数内。 注意:compile函数不能操作指令去递归使用自身的模板或compile函数。编译这些指令将会导致一个无限循环和堆栈溢出错误。可以通过手动使用postLink函数强制编译指令的模板而不是依靠通过template或templateUrl或在compile函数模板手动编译。 link 如果未定义compile属性,则使用此属性。 function link(scope, iElement, iAttrs, controller, transcludeFn) { ... } link函数负责注册DOM监听及更新DOM操作,该函数在模板被克隆后执行。大部分指令逻辑是放在这里面的。 函数参数: scope:被注册监听的指令使用的作用域。 iElement:元素实例,使用该指令的元素。当子元素已被关联,那么只能在postLink函数内操作是安全的。 iAttrs:属性实例,在这个元素上声明的属性,在所有指令的linking函数内共享。 controller:如果至少有一个指令的元素定义一个控制器,那么是个控制器实例。控制器在所有的指令中被共享,它允许指令使用控制器作为通信通道。 transcludeFn:预绑定到正确的嵌入范围的一个linking函数。范围可以通过一个可选的第一个参数重写--function([scope], cloneLinkingFn) pre-linking 函数:在关联子元素之前执行。 Post-linking函数:在关联子元素之后执行。 $compile用法: $compile(element,transclude,maxPriority); element:将要被编译和插入模板的元素或者HTML字符串。 transclude:指令内有效的函数。Function(angular.Scope,cloneAttachFn=) maxPriority:只有在指令比给定的优先级低时应用。只影响根元素,不影响子元素。 返回: 一个用于绑定HTML模板到一个作用域的连接函数。 scope:绑定的作用域。 cloneAttachFn=:如果已提供cloneAttachFn=,则连接函数将克隆模板并且调用cloneAttachFn函数允许去在DOM文档中适当的地方附上克隆的元素。 cloneAttachFn被调用如: cloneAttachFn(clonedElement,scope); clonedElement:一个被传递到编译器的被克隆的原始元素。 scope:当前scope和linking函数执行的地方。 调用linking函数返回模板的元素。有另一个原始元素将被传递,或者克隆的元素被提供了cloneAttachFn。 在连接视图之后直到调用一次$digest()才会更新,这是Angular自动完成的。 如果你需要获得绑定的页面,有两个方法完成: 1.如果你不想在传给编译器和保持这个参考范围之前去请求克隆模板和创建DOM元素:var element = $compile(‘<p>{{value}}</p>’)(scope); 2.另一方面,你需要元素被克隆,从原始的例子中的视图引用将不指向克隆,而是将要被克隆的模板。在这种情况下,你可以通过cloneattachfn访问克隆: var templateElement = angular.element(‘<p>{{value}}</p>’); scope = … ;//定义scope var clonedElement = $compile(templateElement)(scope,function(clonedElement,scope){ //在HTML文档的合适位子添加克隆元素 }) 使用代码(注意:jQLite的选择器功能有限,此处引入了jQuery): <div ng-app="Demo" ng-controller="testCtrl as ctrl"> <div id="contianer">a</div> </div> (function () { angular.module("Demo", []) .service("compileTest", ["$compile",compileTest]) .controller("testCtrl", ["$scope","compileTest",testCtrl]) function compileTest($compile){ this.add = function (s) { var element = angular.element('<span>{{ctrl.words}}</span>'); angular.element("#contianer").append($compile(element)(s)) } }; function testCtrl($scope,compileTest){ var e = angular.element("#contianer"); this.words = "A"; compileTest.add($scope); }; }()); $compile.directive.Attributes 一个包含规范的DOM元素属性并且能在指令的compile和link函数之间共享的对象。这个值反映了当前绑定的状态{{}}。 方法: $addClass(classVal); classVal指定元素该添加的css类。如果一个动画样式是可执行的,那么触发该动画样式。 $removeClass(classVal); classVal指定元素该移除的css类。如果一个动画样式是可执行的,那么触发该动画样式。 $updateClass(newClasses,oldClasses); 更新指定元素的css类。newClasses是新的css类,将要替换oldClasses(已存在样式)。 $observe(key,fn); 观察一个在内部插入的属性。当下一次$digest只会,此观察函数将会被执行一次。当内部插入的值发生变化的时候调用一次此函数。 $set(name,value); 设置DOM元素属性值。name:属性名,value:属性值。 属性: $attr; 元素属性。 使用代码: .red{color:red} .blue{color:blue} <div ng-app="Demo" ng-controller="testCtrl as ctrl"> <div class="blue testClass" data-value="value" new-dir>11111</div> </div> (function () { angular.module("Demo", []) .directive("newDir",newDir) .controller("testCtrl",angular.noop) function newDir(){ return{ restrict:"ACEM", link:function(scope,element,attrs){ attrs.$addClass("red"); attrs.$removeClass("blue"); attrs.$updateClass("newClass","testClass"); element.bind("mouseover",function(){ attrs.$set("data-text","hello"); }); var count = 0; attrs.$observe("data-text",function(){ console.log(count++); }); } } }; }()); 对于指令这块,真的需要多写多用才能真正的理解这些内容及用法... 这篇关于指令的总结文章没多少直接展示的使用代码,不过每个属性都测试过了用法,也写过一些自己项目用的或者自己写着玩的插件... 好了,暂时写到这,接下来去学习另外的服务...
文章
JavaScript  ·  前端开发  ·  编译器  ·  安全
2015-11-16
AngularJS学习笔记--002--Angular JS路由插件ui.router源码解析
路由(route),几乎所有的MVC(VM)框架都应该具有的特性,因为它是前端构建单页面应用(SPA)必不可少的组成部分。 那么,对于angular而言,它自然也有内置的路由模块:叫做ngRoute。 不过,大家很少用它,因为它的功能太有限,往往不能满足开发需求!! 于是,一个基于ngRoute开发的第三方路由模块,叫做ui.router,受到了大家的“追捧”。 ngRoute vs ui.router 首先,无论是使用哪种路由,作为框架额外的附加功能,它们都将以模块依赖的形式被引入,简而言之就是:在引入路由源文件之后,你的代码应该这样写(以ui.router为例): angular.module("myApp", ["ui.router"]); // myApp为自定义模块,依赖第三方路由模块ui.router 这样做的目的是:在程序启动(bootstrap)的时候,加载依赖模块(如:ui.router),将所有挂载在该模块的服务(provider),指令(directive),过滤器(filter)等都进行注册,那么在后面的程序中便可以调用了。 说到这里,就得看看ngRoute模块和ui.router模块各自都提供了哪些服务,哪些指令? ngRoute $routeProvider(服务提供者) --------- 对应于下面的urlRouterProvider和stateProvider $route(服务) --------- 对应于下面的urlRouter和state $routeParams(服务) --------- 对应于下面的stateParams ng-view(指令) --------- 对应于下面的ui-view ui.router $urlRouterProvider(服务提供者) --------- 用来配置路由重定向 $urlRouter(服务) $stateProvider(服务提供者) --------- 用来配置路由 $state(服务) --------- 用来显示当前路由状态信息,以及一些路由方法(如:跳转) $stateParams(服务) --------- 用来存储路由匹配时的参数 ui-view(指令) --------- 路由模板渲染,对应的dom相关联 ui-sref(指令) ... (注:服务提供者:用来提供服务实例和配置服务。) 这样一看,其实ui.router和ngRoute大体的设计思路,对应的模块划分都是一致的(毕竟是同一个团队开发),不同的地方在于功能点的实现和增强。 那么问题来了:ngRoute弱在哪些方面,ui.router怎么弥补了这些方面? 这里,列举两个最重要的方面来说(其他细节,后面再说): 多视图 嵌套视图 多视图 多视图:页面可以显示多个动态变化的不同区块。 这样的业务场景是有的: 比如:页面一个区块用来显示页面状态,另一个区块用来显示页面主内容,当路由切换时,页面状态跟着变化,对应的页面主内容也跟着变化。 首先,我们尝试着用ngRoute来做: html <div ng-view>区块1</div> <div ng-view>区块2</div> js $routeProvider .when('/', { template: 'hello world' }); 我们在html中利用ng-view指令定义了两个区块,于是两个div中显示了相同的内容,这很合乎情理,但却不是我们想要的,但是又不能为力,因为,在ngRoute中: 视图没有名字进行唯一标志,所以它们被同等的处理。 路由配置只有一个模板,无法配置多个。 ok,针对上述两个问题,我们尝试用ui.router来做: html <div ui-view></div> <div ui-view="status"></div> js $stateProvider .state('home', { url: '/', views: { '': { template: 'hello world' }, 'status': { template: 'home page' } } }); 这次,结果是我们想要的,两个区块,分别显示了不同的内容,原因在于,在ui.router中: 可以给视图命名,如:ui-view="status"。 可以在路由配置中根据视图名字(如:status),配置不同的模板(其实还有controller等)。 注:视图名是一个字符串,不可以包含@(原因后面会说)。 嵌套视图 嵌套视图:页面某个动态变化区块中,嵌套着另一个可以动态变化的区块。 这样的业务场景也是有的: 比如:页面一个主区块显示主内容,主内容中的部分内容要求根据路由变化而变化,这时就需要另一个动态变化的区块嵌套在主区块中。 其实,嵌套视图,在html中的最终表现就像这样: <div ng-view> I am parent <div ng-view>I am child</div> </div> 转成JavaScript,我们会在程序里这样写: $routeProvider .when('/', { template: 'I am parent <div ng-view>I am child</div>' }); 倘若,你真的用ngRoute这样写,你会发现浏览器崩溃了,因为在ng-view指令link的过程中,代码会无限递归下去。 那么造成这种现象的最根本原因:路由没有明确的父子层级关系! 看看ui.router是如何解决这一问题的? $stateProvider .state('parent', { abstract: true, url: '/', template: 'I am parent <div ui-view></div>' }) .state('parent.child', { url: '', template: 'I am child' }); 巧妙地,通过parent与parent.child来确定路由的父子关系,从而解决无限递归问题。 另外子路由的模板最终也将被插入到父路由模板的div[ui-view]中去,从而达到视图嵌套的效果。 ui.router工作原理 路由,大致可以理解为:一个查找匹配的过程。 对于前端MVC(VM)而言,就是将hash值(#xxx)与一系列的路由规则进行查找匹配,匹配出一个符合条件的规则,然后根据这个规则,进行数据的获取,以及页面的渲染。 所以,接下来: 第一步,学会如何创建路由规则? 第二步,了解路由查找匹配原理? 路由的创建 首先,看一个简单的例子: $stateProvider .state('home', { url: '/abc', template: 'hello world' }); 上面,我们通过调用$stateProvider.state(...)方法,创建了一个简单路由规则,通过参数,可以容易理解到: 规则名:'home' 匹配的url:'/abc' 对应的模板:'hello world' 意思就是说:当我们访问http://xxxx#/abc的时候,这个路由规则被匹配到,对应的模板会被填到某个div[ui-view]中。 看上去似乎很简单,那是因为我们还没有深究具体的一些路由配置参数(我们后面再说)。 这里需要深入的是:$stateProvider.state(...)方法,它做了些什么工作? 首先,创建并存储一个state对象,里面包含着该路由规则的所有配置信息。 然后,调用$urlRouterProvider.when(...)方法,进行路由的注册(之前是路由的创建),代码里是这样写的: $urlRouterProvider.when(state.url, ['$match', '$stateParams', function ($match, $stateParams) { // 判断是否是同一个state || 当前匹配参数是否相同 if ($state.$current.navigable != state || !equalForKeys($match, $stateParams)) { $state.transitionTo(state, $match, { inherit: true, location: false }); } }]); 上述代码的意思是:当hash值与state.url相匹配时,就执行后面那段回调,回调函数里面进行了两个条件判断之后,决定是否需要跳转到该state? 这里就插入了一个话题:为什么说 “跳转到该state,而不是该url”? 其实这个问题跟大家一直说的:“ui.router是基于state(状态)的,而不是url”是同一个问题。 我的理解是这样的:之前就说过,路由存在着明确的父子关系,每一个路由可以理解为一个state, 当程序匹配到某一个子路由时,我们就认为这个子路由state被激活,同时,它对应的父路由state也将被激活。 我们还可以手动的激活某一个state,就像上面写的那样,$state.transitionTo(state, ...);,这样的话,它的父state会被激活(如果还没有激活的话),它的子state会被销毁(如果已经激活的话)。 ok,回到之前的路由注册,调用了$urlRouterProvider.when(...)方法,它做了什么呢? 它创建了一个rule,并存储在rules集合里面,之后的,每次hash值变化,路由重新查找匹配都是通过遍历这个rules集合进行的。 路由的查找匹配 有了之前,路由的创建和注册,接下来,自然会想到路由是如何查找匹配的? 恐怕,这得从页面加载完毕说起: angular 在刚开始的digest时,‘rootScope会触发locationChangeSuccess‘事件(angular在每次浏览器hashchange的时候也会触发‘locationChangeSuccess`事件) ui.router 监听了$locationChangeSuccess事件,于是开始通过遍历一系列rules,进行路由查找匹配 当匹配到路由后,就通过$state.transitionTo(state,...),跳转激活对应的state 最后,完成数据请求和模板的渲染 可以从下面这段源代码看到,看到查找匹配的起始和过程: function update(evt) { // ...省略 function check(rule) { var handled = rule($injector, $location); // handled可以是返回: // 1. 新的的url,用于重定向 // 2. false,不匹配 // 3. true,匹配 if (!handled) return false; if (isString(handled)) $location.replace().url(handled); return true; } var n = rules.length, i; // 渲染遍历rules,匹配到路由,就停止循环 for (i = 0; i < n; i++) { if (check(rules[i])) return; } // 如果都匹配不到路由,使用otherwise路由(如果设置了的话) if (otherwise) check(otherwise); } function listen() { // 监听$locationChangeSuccess,开始路由的查找匹配 listener = listener || $rootScope.$on('$locationChangeSuccess', update); return listener; } if (!interceptDeferred) listen(); 那么,问题来了:难道每次路由变化(hash变化),由于监听了’$locationChangeSuccess'事件,都要进行rules的遍历来查找匹配路由,然后跳转到对应的state吗? 答案是:肯定的,一般的路由器都是这么做的,包括ngRoute。 那么ui.router对于这样的问题,会怎么进行优化呢? 回归到问题:我们之所以要循环遍历rules,是因为要查找匹配到对应的路由(state),然后跳转过去,倘若不循环,能直接找到对应的state吗? 答案是:可以的。 还记得前面说过,在用ui.router在创建路由时: 会实例化一个对应的state对象,并存储起来(states集合里面) 每一个state对象都有一个state.name进行唯一标识(如:'home') 根据以上两点,于是ui.router提供了另一个指令叫做:ui-sref指令,来解决这个问题,比如这样: <a ui-sref="home">通过ui-sref跳转到home state</a> 当点击这个a标签时,会直接跳转到home state,而并不需要循环遍历rules,ui.router是这样做到的(这里简单说一下): 首先,ui-sref="home"指令会给对应的dom添加click事件,然后根据state.name,直接跳转到对应的state,代码像这样: element.bind("click", function(e) { // ..省略若干代码 var transition = $timeout(function() { // 手动跳转到指定的state $state.go(ref.state, params, options); }); }); 跳转到对应的state之后,ui.router会做一个善后处理,就是改变hash,所以理所当然,会触发’$locationChangeSuccess'事件,然后执行回调,但是在回调中可以通过一个判断代码规避循环rules,像这样: function update(evt) { var ignoreUpdate = lastPushedUrl && $location.url() === lastPushedUrl; // 手动调用$state.go(...)时,直接return避免下面的循环 if (ignoreUpdate) return true; // 省略下面的循环ruls代码 } 说了那么多,其实就是想说,我们不建议直接使用href="#/xxx"来改变hash,然后跳转到对应state(虽然也是可以的),因为这样做会多了一步rules循环遍历,浪费性能,就像下面这样: <a href="#/abc">通过href跳转到home state</a> 路由详解 这里详细地介绍ui.router的参数配置和一些深层次用法。 不过,在这之前,需要一个demo,ui.router的官网demo无非就是最好的学习例子,里面涉及了大部分的知识点,所以接下来的代码讲解大部分都会是这里面的(建议下载到本地进行代码学习)。 为了更好的学习这个demo,我画了一张图来描述这个demo的contacts部分各个视图模块,如下: 父与子 之前就说到,在ui.router中,路由就有父与子的关系(多个父与子凑起来就有了,祖先和子孙的关系),从javascript的角度来说,其实就是路由对应的state对象之间存在着某种引用的关系。 用一张数据结构的表示下contacts部分,大概是这样(原图): 上面的图看着有点乱,不过没关系,起码能看出各个state对象之间通过parent字段维系了这样一个父与子的关系(粉红色的线)。 ok,接下来就看下是如何定义路由的父子关系的? 假设有一个父路由,如下: $stateProvider .state('contacts', {}); ui.router提供了几种方法来定义它的子路由: 1.点标记法(推荐) $stateProvider .state('contacts.list', {}); 通过状态名简单明了地来确定父子路由关系,如:状态名为'a.b.c'的路由,对应的父路由就是状态名为'a.b'路由。 2.parent属性 $stateProvider .state({ name: 'list', // 状态名也可以直接在配置里指定 parent: 'contacts' // 父路由的状态名 }); 或者: $stateProvider .state({ name: 'list', // 状态名也可以直接在配置里指定 parent: { // parent也可以是一个父路由配置对象(指定路由的状态名即可) name: 'contacts' } }); 通过parent直接指定父路由,可以是父路由的状态名(字符串),也可以是一个包含状态名的父路由配置(对象)。 竟然路由有了父与子的关系,那么它们的注册顺序有要求嘛? 答案是:没有要求,我们可以在父路由存在之前,创建子路由(不过,不是很推荐),因为ui.router在遇到这种情况时,在内部会帮我们先缓存子路由的信息,等待它的父路由注册完毕后,再进行子路由的注册。 模板渲染 当路由成功跳转到指定的state时,ui.router会触发'$stateChangeSuccess'事件通知所有的ui-view进行模板重新渲染。 代码是这样的: if (options.notify) { $rootScope.$broadcast('$stateChangeSuccess', to.self, toParams, from.self, fromParams); } 而ui-view指令在进行link的时候,在其内部就已经监听了这一事件(消息),来随时更新视图: scope.$on('$stateChangeSuccess', function() { updateView(false); }); 大体的模板渲染过程就是这样的,这里遇到一个问题,就是:每一个 div[ui-view]在重新渲染的时候如何获取到对应视图模板的呢? 要想知道这个答案, 首先,我们得先看一下模板如何设置? 一般在设置单视图的时候,我们会这样做: $stateProvider .state('contacts', { abstract: true, url: '/contacts', templateUrl: 'app/contacts/contacts.html' }); 在配置对象里面,我们用templateUrl指定模板路径即可。 如果我们需要设置多视图,就需要用到views字段,像这样: $stateProvider .state('contacts.detail', { url: '/{contactId:[0-9]{1,4}}', views: { '' : { templateUrl: 'app/contacts/contacts.detail.html', }, 'hint@': { template: 'This is contacts.detail populating the "hint" ui-view' }, 'menuTip': { templateProvider: ['$stateParams', function($stateParams) { return '<hr><small class="muted">Contact ID: ' + $stateParams.contactId + '</small>'; }] } } }); 这里我们使用了另外两种方式设置模板: template:直接指定模板内容,另外也可以是函数返回模板内容 templateProvider:通过依赖注入的调用函数的方式返回模板内容 上述我们介绍了设置单视图和多视图模板的方式,其实最终它们在ui.router内部都会被统一格式化成的views的形式,且它们的key值会做特殊变化: 上述的单视图会变成这样: views: { // 模板内容会被安插在根路由模板(index.html)的匿名视图下 '@': { abstract: true, url: '/contacts', templateUrl: 'app/contacts/contacts.html' } } 多视图会变成这样: views: { // 模板内容会被安插在父路由(contacts)模板的匿名视图下 '@contacts': { templateUrl: 'app/contacts/contacts.detail.html', }, // 模板内容会被安插在根路由(index.html)模板的名为hint视图下 'hint@': { template: 'This is contacts.detail populating the "hint" ui-view' }, // 模板内容会被安插在父路由(contacts)模板的名为menuTip视图下 'menuTip@contacts': { templateProvider: ['$stateParams', function($stateParams) { return '<hr><small class="muted">Contact ID: ' + $stateParams.contactId + '</small>'; }] } } 我们会发现views对象里面的key变化了,最明显的是出现了一个@符号,其实这样的key值是ui.router的一个设计,它的原型是:viewName + '@' + stateName,解释下: viewName 指的是ui-view="status"中的'status' 也可以是''(空字符串),因为会有匿名的ui-view或者ui-view="" stateName 默认情况下是父路由的state.name,因为子路由模板一般都安插在父路由的ui-view中 也可以是''(空字符串),表示最顶层rootState 还可以是任意的祖先state.name 这样原型的意思是,表示该模板将会被安插在名为stateName路由对应模板的viewName视图下(可以看看上面代码中的注释理解下)。 其实这也解释了之前我说的:“为什么state.name里面不能存在@符号”?因为@在这里被用于特殊含义了。 所以,到这里,我们就知道在ui-view重新进行模板渲染时,是根据viewName + '@' + stateName来获取对应的视图模板内容(其实还有controller等)的。 其实,由于路由有了父与子的关系,某种程度上就有了override(覆盖或者重写)可能。 父路由和子路由之间就存在着视图的override,像下面这段代码: $stateProvider .state('contacts.detail', { url: '/{contactId:[0-9]{1,4}}', views: { 'hint@': { template: 'This is contacts.detail populating the "hint" ui-view' } } }); $stateProvider .state('contacts.detail.item', { url: '/item/:itemId', views: { 'hint@': { template: ' This is contacts.detail.item overriding the "hint" ui-view' } } }); 上面两个路由(state)存在着父与子的关系,且他们都对@hint定义了视图,那么当子路由被激活时(它的父路由也会被激活),我们应该选择哪个视图配置呢? 答案是:子路由的配置。 具体的,ui.router是如何实现这样的视图override的呢? 简单地回答就是:通过javascript原型链实现的,你可以在每次路由切换成功后,尝试着打印出$state.current.locals这个变量一看究竟。 还有一个很重要的问题,关乎性能:当我们子路由变化时,页面中所有的ui-view都会重新进行渲染吗? 答案是:不会,只会从子路由对应的视图开始局部重新渲染。 在每次路由变化时,ui.router会记录变化的子路由,并对子路由进行重新的预处理(包括controller,reslove等),最后局部更新对应的ui-view,父路由部分是不会有任何变化的。 controller控制器 有了模板之后,必然不可缺少controller向模板对应的作用域(scope)中填写数据,这样才可以渲染出动态数据。 我们可以为每一个视图添加不同的controller,就像下面这样: $stateProvider .state('contacts', { abstract: true, url: '/contacts', templateUrl: 'app/contacts/contacts.html', resolve: { 'contacts': ['contacts', function( contacts){ return contacts.all(); }] }, controller: ['$scope', '$state', 'contacts', 'utils', function ($scope, $state, contacts, utils) { // 向作用域写数据 $scope.contacts = contacts; }] }); 注意:controller是可以进行依赖注入的,它注入的对象有两种: 已经注册的服务(service),如:$state,utils 上面的reslove定义的解决项(这个后面来说),如:contacts 但是不管怎样,目的都是:向作用域里写数据。 reslove解决项 resolve在state配置参数中,是一个对象(key-value),每一个value都是一个可以依赖注入的函数,并且返回的是一个promise(当然也可以是值,resloved defer)。 我们通常会在resolve中,进行数据获取的操作,然后返回一个promise,就像这样: resolve: { 'contacts': ['contacts', function( contacts){ return contacts.all(); }] } 上面有好多contacts,为了不混淆,我改一下代码: resolve: { 'myResolve': ['contacts', function(contacts){ return contacts.all(); }] } 这样就看清了,我们定义了resolve,包含了一个myResolve的key,它对应的value是一个函数,依赖注入了一个服务contacts,调用了contacts.all()方法并返回了一个promise。 于是我们便可以在controller中引用myResolve,像这样: controller: ['$scope', '$state', 'myResolve', 'utils', function ($scope, $state, contacts, utils) { // 向作用域写数据 $scope.contacts = contacts; }] 这样做的目的: 简化了controller的操作,将数据的获取放在resolve中进行,这在多个视图多个controller需要相同数据时,有一定的作用。 只有当reslove中的promise全部resolved(即数据获取成功)后,才会触发'$stateChangeSuccess'切换路由,进而实例化controller,然后更新模板。 另外,子路由的resolve或者controller都是可以依赖注入父路由的resolve提供的数据服务,就像这样: $stateProvider .state('parent', { url: '', resolve: { parent: ['$q', '$timeout', function ($q, $timeout) { var defer = $q.defer(); $timeout(function () { defer.resolve('parent'); }, 1000); return defer.promise; }] }, template: 'I am parent <div ui-view></div>' }) .state('parent.child', { url: '/child', resolve: { child: ['parent', function (parent) { // 调用父路由的解决项 return parent + ' and child'; }] }, controller: ['child', 'parent', function (child, parent) { // 调用自身的解决项,以及父路由的解决项 console.log(child, parent); }], template: 'I am child' }); 另外每一个视图也可以单独定义自己的resolve和controller,它们也是可以依赖注入自身的state.resolve,或者view下的resolve,或者父路由的reslove,就像这样: html <div ui-view></div> <div ui-view="status"></div> javascript: $stateProvider .state('home', { url: '/home', resolve: { common: ['$q', '$timeout', function ($q, $timeout) { // 公共的resolve var defer = $q.defer(); $timeout(function () { defer.resolve('common data'); }, 1000); return defer.promise; }], }, views: { '': { resolve: { special: ['common', function (common) { // 访问state.resolve console.log(common); }] } }, 'status': { resolve: { common: function () { // 重写state.resolve return 'override common data' } }, controller: ['common', function (common) { // 访问视图自身的resolve console.log(common); }] } } }); 总结一下: 路由的controller除了可以依赖注入正常的service,也可以依赖注入resolve 子路由的resolve可以依赖注入父路由的resolve,也可以重写父路由的resolve供controller调用 路由可以有单独的state.resolve之外,还可以在views视图中单独配置resolve,视图resolve是可以依赖注入自身state.resolve甚至是父路由的state.resolve
文章
存储  ·  JavaScript  ·  前端开发  ·  Go  ·  网络架构  ·  缓存  ·  C++
2016-12-13
java-学习-自我规划
一、基础篇 1.1 JVM 1.1.1. Java内存模型,Java内存管理,Java堆和栈,垃圾回收http://www.jcp.org/en/jsr/detail?id=133http://ifeve.com/jmm-faq/ 1.1.2. 了解JVM各种参数及调优 1.1.3. 学习使用Java工具 jps, jstack, jmap, jconsole, jinfo, jhat, javap, …http://kenai.com/projects/btracehttp://www.crashub.org/https://github.com/taobao/TProfilerhttps://github.com/CSUG/HouseMDhttp://wiki.cyclopsgroup.org/jmxtermhttps://github.com/jlusdy/TBJMap 1.1.4. 学习Java诊断工具http://www.eclipse.org/mat/http://visualvm.java.net/oqlhelp.html 1.1.5. 自己编写各种outofmemory,stackoverflow程序 HeapOutOfMemory Young OutOfMemory MethodArea OutOfMemory ConstantPool OutOfMemory DirectMemory OutOfMemory Stack OutOfMemory Stack OverFlow 1.1.6. 使用工具尝试解决以下问题,并写下总结 当一个Java程序响应很慢时如何查找问题 当一个Java程序频繁FullGC时如何解决问题,如何查看垃圾回收日志 当一个Java应用发生OutOfMemory时该如何解决,年轻代、年老代、永久代解决办法不同,导致原因也不同 1.1.7. 参考资料http://docs.oracle.com/javase/specs/jvms/se7/html/http://www.cs.umd.edu/~pugh/java/memoryModel/http://gee.cs.oswego.edu/dl/jmm/cookbook.html 1.2. Java基础知识 1.2.1. 阅读源代码 java.lang.String java.lang.Integer java.lang.Long java.lang.Enum java.math.BigDecimal java.lang.ThreadLocal java.lang.ClassLoader & java.net.URLClassLoader java.util.ArrayList & java.util.LinkedList java.util.HashMap & java.util.LinkedHashMap & java.util.TreeMap java.util.HashSet & java.util.LinkedHashSet & java.util.TreeSet 1.2.2. 熟悉Java中各种变量类型 1.2.3. 熟悉Java String的使用,熟悉String的各种函数 1.2.4. 熟悉Java中各种关键字 1.2.5. 学会使用List,Map,Stack,Queue,Set 上述数据结构的遍历 上述数据结构的使用场景 Java实现对Array/List排序 java.uti.Arrays.sort() java.util.Collections.sort() Java实现对List去重 Java实现对List去重,并且需要保留数据原始的出现顺序 Java实现最近最少使用cache,用LinkedHashMap 1.2.6. Java IO&Java NIO,并学会使用 java.io. java.nio. nio和reactor设计模式 文件编码,字符集 1.2.7. Java反射与javassist 反射与工厂模式 java.lang.reflect. 1.2.8. Java序列化 java.io. Serializable 什么是序列化,为什么序列化 序列化与单例模式 google序列化protobuf 1.2.9. 虚引用,弱引用,软引用 java.lang.ref. 实验这些引用的回收 1.2.10. 熟悉Java系统属性 java.util.Properties 1.2.11. 熟悉Annotation用法 java.lang.annotation. 1.2.12. JMS javax.jms. 1.2.13. JMX java.lang.management. javax.management. 1.2.14. 泛型和继承,泛型和擦除 1.2.15. 自动拆箱装箱与字节码 1.2.16. 实现Callback 1.2.17. java.lang.Void类使用 1.2.18. Java Agent,premain函数 java.lang.instrument 1.2.19. 单元测试 Junit,http://junit.org/ Jmockit,https://code.google.com/p/jmockit/ djUnit,http://works.dgic.co.jp/djunit/ 1.2.20. Java实现通过正则表达式提取一段文本中的电子邮件,并将@替换为#输出 java.lang.util.regex. 1.2.21. 学习使用常用的Java工具库 commons.lang, commons.… guava-libraries netty 1.2.22. 什么是API&SPIhttp://en.wikipedia.org/wiki/Application_programming_interfacehttp://en.wikipedia.org/wiki/Service_provider_interface 1.2.23. 参考资料 JDK src.zip 源代码http://openjdk.java.net/http://commons.apache.org/https://code.google.com/p/guava-libraries/http://netty.io/http://stackoverflow.com/questions/2954372/difference-between-spi-and-apihttp://stackoverflow.com/questions/11404230/how-to-implement-the-api-spi-pattern-in-java 1.3. Java并发编程 1.3.1. 阅读源代码,并学会使用 java.lang.Thread java.lang.Runnable java.util.concurrent.Callable java.util.concurrent.locks.ReentrantLock java.util.concurrent.locks.ReentrantReadWriteLock java.util.concurrent.atomic.Atomic* java.util.concurrent.Semaphore java.util.concurrent.CountDownLatch java.util.concurrent.CyclicBarrier java.util.concurrent.ConcurrentHashMap java.util.concurrent.Executors 1.3.2. 学习使用线程池,自己设计线程池需要注意什么 1.3.3. 锁 什么是锁,锁的种类有哪些,每种锁有什么特点,适用场景是什么 在并发编程中锁的意义是什么 1.3.4. synchronized的作用是什么,synchronized和lock 1.3.5. sleep和wait 1.3.6. wait和notify 1.3.7. 写一个死锁的程序 1.3.8. 什么是守护线程,守护线程和非守护线程的区别以及用法 1.3.9. volatile关键字的理解 C++ volatile关键字和Java volatile关键字 happens-before语义 编译器指令重排和CPU指令重排http://en.wikipedia.org/wiki/Memory_orderinghttp://en.wikipedia.org/wiki/Volatile_variablehttp://preshing.com/20130702/the-happens-before-relation/ 1.3.10. 以下代码是不是线程安全?为什么?如果为count加上volatile修饰是否能够做到线程安全?你觉得该怎么做是线程安全的? public class Sample { private static int count = 0; public static void increment() { count++; } } 1.3.11. 解释一下下面两段代码的差别 // 代码1 public class Sample { private static int count = 0; synchronized public static void increment() { count++; } } // 代码2 public class Sample { private static AtomicInteger count = new AtomicInteger(0); public static void increment() { count.getAndIncrement(); } } 1.3.12. 参考资料http://book.douban.com/subject/10484692/http://www.intel.com/content/www/us/en/processors/architectures-software-developer-manuals.html 二、 进阶篇 2.1. Java底层知识 2.1.1. 学习了解字节码、class文件格式http://en.wikipedia.org/wiki/Java_class_filehttp://en.wikipedia.org/wiki/Java_bytecodehttp://en.wikipedia.org/wiki/Java_bytecode_instruction_listingshttp://www.csg.ci.i.u-tokyo.ac.jp/~chiba/javassist/http://asm.ow2.org/ 2.1.2. 写一个程序要求实现javap的功能(手工完成,不借助ASM等工具) 如Java源代码: public static void main(String[] args) { int i = 0; i += 1; i *= 1; System.out.println(i); } 编译后读取class文件输出以下代码: public static void main(java.lang.String[]); Code: Stack=2, Locals=2, Args_size=1 0: iconst_0 1: istore_1 2: iinc 1, 1 5: iload_1 6: iconst_1 7: imul 8: istore_1 9: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream; 12: iload_1 13: invokevirtual #3; //Method java/io/PrintStream.println:(I)V 16: return LineNumberTable: line 4: 0 line 5: 2 line 6: 5 line 7: 9 line 8: 16 2.1.3. CPU缓存,L1,L2,L3和伪共享http://duartes.org/gustavo/blog/post/intel-cpu-caches/http://mechanical-sympathy.blogspot.com/2011/07/false-sharing.html 2.1.4. 什么是尾递归 2.1.5. 熟悉位运算 用位运算实现加、减、乘、除、取余 2.1.6. 参考资料http://book.douban.com/subject/1138768/http://book.douban.com/subject/6522893/http://en.wikipedia.org/wiki/Java_class_filehttp://en.wikipedia.org/wiki/Java_bytecodehttp://en.wikipedia.org/wiki/Java_bytecode_instruction_listings 2.2. 设计模式 2.2.1. 实现AOP CGLIB和InvocationHandler的区别http://cglib.sourceforge.net/ 动态代理模式 Javassist实现AOPhttp://www.csg.ci.i.u-tokyo.ac.jp/~chiba/javassist/ ASM实现AOPhttp://asm.ow2.org/ 2.2.2. 使用模板方法设计模式和策略设计模式实现IOC 2.2.3. 不用synchronized和lock,实现线程安全的单例模式 2.2.4. nio和reactor设计模式 2.2.5. 参考资料http://asm.ow2.org/http://cglib.sourceforge.net/http://www.javassist.org/ 2.3. 网络编程知识 2.3.1. Java RMI,Socket,HttpClient 2.3.2. 用Java写一个简单的静态文件的HTTP服务器 实现客户端缓存功能,支持返回304 实现可并发下载一个文件 使用线程池处理客户端请求 使用nio处理客户端请求 支持简单的rewrite规则 上述功能在实现的时候需要满足“开闭原则” 2.3.3. 了解nginx和apache服务器的特性并搭建一个对应的服务器http://nginx.org/http://httpd.apache.org/ 2.3.4. 用Java实现FTP、SMTP协议 2.3.5. 什么是CDN?如果实现?DNS起到什么作用? 搭建一个DNS服务器 搭建一个 Squid 或 Apache Traffic Server 服务器http://www.squid-cache.org/http://trafficserver.apache.org/http://en.wikipedia.org/wiki/Domain_Name_System 2.3.6. 参考资料http://www.ietf.org/rfc/rfc2616.txthttp://tools.ietf.org/rfc/rfc5321.txthttp://en.wikipedia.org/wiki/Open/closed_principle 2.4. 框架知识 spring,spring mvc,阅读主要源码 ibatis,阅读主要源码 用spring和ibatis搭建java server 2.5. 应用服务器知识 熟悉使用jboss,https://www.jboss.org/overview/ 熟悉使用tomcat,http://tomcat.apache.org/ 熟悉使用jetty,http://www.eclipse.org/jetty/ 三、 高级篇 3.1. 编译原理知识 3.1.1. 用Java实现以下表达式解析并返回结果(语法和Oracle中的select sysdate-1 from dual类似) sysdate sysdate - 1 sysdate - 1/24 sysdate - 1/(12*2) 3.1.2. 实现对一个List通过DSL筛选 QList<map> mapList = new QList<map>; mapList.add({“name”: “hatter test”}); mapList.add({“id”: -1,”name”: “hatter test”}); mapList.add({“id”: 0, “name”: “hatter test”}); mapList.add({“id”: 1, “name”: “test test”}); mapList.add({“id”: 2, “name”: “hatter test”}); mapList.add({“id”: 3, “name”: “test hatter”}); mapList.query(“id is not null and id > 0 and name like ‘%hatter%’”); 要求返回列表中匹配的对象,即最后两个对象; 3.1.3. 用Java实现以下程序(语法和变量作用域处理都和JavaScript类似): 代码: var a = 1; var b = 2; var c = function() { var a = 3; println(a); println(b); }; c(); println(a); println(b); 输出: 3 2 1 2 3.1.4. 参考资料http://en.wikipedia.org/wiki/Abstract_syntax_treehttps://javacc.java.net/http://www.antlr.org/ 3.2. 操作系统知识 Ubuntu Centos 使用linux,熟悉shell脚本 3.3. 数据存储知识 3.3.1. 关系型数据库 MySQL 如何看执行计划 如何搭建MySQL主备 binlog是什么 Derby,H2,PostgreSQL SQLite 3.3.2. NoSQL Cache Redis Memcached Leveldb Bigtable HBase Cassandra Mongodb 图数据库 neo4j 3.3.3. 参考资料http://db-engines.com/en/rankinghttp://redis.io/https://code.google.com/p/leveldb/http://hbase.apache.org/http://cassandra.apache.org/http://www.mongodb.org/http://www.neo4j.org/ 3.4. 大数据知识 3.4.1. Zookeeper,在linux上部署zk 3.4.2. Solr,Lucene,ElasticSearch 在linux上部署solr,solrcloud,,新增、删除、查询索引 3.4.3. Storm,流式计算,了解Spark,S4 在linux上部署storm,用zookeeper做协调,运行storm hello world,local和remote模式运行调试storm topology。 3.4.4. Hadoop,离线计算 Hdfs:部署NameNode,SecondaryNameNode,DataNode,上传文件、打开文件、更改文件、删除文件 MapReduce:部署JobTracker,TaskTracker,编写mr job Hive:部署hive,书写hive sql,得到结果 Presto:类hive,不过比hive快,非常值得学习 3.4.5. 分布式日志收集flume,kafka,logstash 3.4.6. 数据挖掘,mahout 3.4.7. 参考资料http://zookeeper.apache.org/https://lucene.apache.org/solr/https://github.com/nathanmarz/storm/wikihttp://hadoop.apache.org/http://prestodb.io/http://flume.apache.org/,http://logstash.net/,http://kafka.apache.org/http://mahout.apache.org/ 3.5. 网络安全知识 3.5.1. 什么是DES、AES 3.5.2. 什么是RSA、DSA 3.5.3. 什么是MD5,SHA1 3.5.4. 什么是SSL、TLS,为什么HTTPS相对比较安全 3.5.5. 什么是中间人攻击、如果避免中间人攻击 3.5.6. 什么是DOS、DDOS、CC攻击 3.5.7. 什么是CSRF攻击 3.5.8. 什么是CSS攻击 3.5.9. 什么是SQL注入攻击 3.5.10. 什么是Hash碰撞拒绝服务攻击 3.5.11. 了解并学习下面几种增强安全的技术 http://www.openauthentication.org/ HOTP http://www.ietf.org/rfc/rfc4226.txt TOTP http://tools.ietf.org/rfc/rfc6238.txt OCRA http://tools.ietf.org/rfc/rfc6287.txthttp://en.wikipedia.org/wiki/Salt_(cryptography) 3.5.12. 用openssl签一个证书部署到apache或nginx 3.5.13. 参考资料http://en.wikipedia.org/wiki/Cryptographic_hash_functionhttp://en.wikipedia.org/wiki/Block_cipherhttp://en.wikipedia.org/wiki/Public-key_cryptographyhttp://en.wikipedia.org/wiki/Transport_Layer_Securityhttp://www.openssl.org/https://code.google.com/p/google-authenticator/ 四、 扩展篇 4.1. 相关知识 4.1.1. 云计算,分布式,高可用,可扩展 4.1.2. 虚拟化https://linuxcontainers.org/http://www.linux-kvm.org/page/Main_Pagehttp://www.xenproject.org/https://www.docker.io/ 4.1.3. 监控http://www.nagios.org/http://ganglia.info/ 4.1.4. 负载均衡http://www.linuxvirtualserver.org/ 4.1.5. 学习使用githttps://github.com/https://git.oschina.net/ 4.1.6. 学习使用mavenhttp://maven.apache.org/ 4.1.7. 学习使用gradlehttp://www.gradle.org/ 4.1.8. 学习一个小语种语言 Groovy Scala LISP, Common LISP, Schema, Clojure R Julia Lua Ruby 4.1.9. 尝试了解编码的本质 了解以下概念 ASCII, ISO-8859-1 GB2312, GBK, GB18030 Unicode, UTF-8 不使用 String.getBytes() 等其他工具类/函数完成下面功能 public static void main(String[] args) throws IOException { String str = “Hello, 我们是中国人。”; byte[] utf8Bytes = toUTF8Bytes(str); FileOutputStream fos = new FileOutputStream(“f.txt”); fos.write(utf8Bytes); fos.close(); } public static byte[] toUTF8Bytes(String str) { return null; // TODO } 想一下上面的程序能不能写一个转GBK的? 写个程序自动判断一个文件是哪种编码 4.1.10. 尝试了解时间的本质 时区 & 冬令时、夏令时http://en.wikipedia.org/wiki/Time_zone ftp://ftp.iana.org/tz/data/asiahttp://zh.wikipedia.org/wiki/%E4%B8%AD%E5%9C%8B%E6%99%82%E5%8D%80 闰年http://en.wikipedia.org/wiki/Leap_year 闰秒 ftp://ftp.iana.org/tz/data/leapseconds System.currentTimeMillis() 返回的时间是什么 4.1.11. 参考资料http://git-scm.com/http://en.wikipedia.org/wiki/UTF-8http://www.iana.org/time-zones 4.2. 扩展学习 4.2.1. JavaScript知识 4.2.1.1. 什么是prototype 修改代码,使程序输出“1 3 5”:http://jsfiddle.net/Ts7Fk/ 4.2.1.2. 什么是闭包 看一下这段代码,并解释一下为什么按Button1时没有alert出“This is button: 1”,如何修改:http://jsfiddle.net/FDPj3/1/ 4.2.1.3. 了解并学习一个JS框架 jQuery ExtJS ArgularJS 4.2.1.4. 写一个Greasemonkey插件 http://en.wikipedia.org/wiki/Greasemonkey 4.2.1.5. 学习node.jshttp://nodejs.org/ 4.2.2. 学习html5 ArgularJS,https://docs.angularjs.org/api 4.2.3. 参考资料http://www.ecmascript.org/http://jsfiddle.net/http://jsbin.com/http://runjs.cn/http://userscripts.org/ 五、 推荐书籍 《深入Java虚拟机》 《深入理解Java虚拟机》 《Effective Java》 《七周七语言》 《七周七数据》 《Hadoop技术内幕》 《Hbase In Action》 《Mahout In Action》 《这就是搜索引擎》 《Solr In Action》 《深入分析Java Web技术内幕》 《大型网站技术架构》 《高性能MySQL》 《算法导论》 《计算机程序设计艺术》 《代码大全》 《JavaScript权威指南》
文章
SQL  ·  安全  ·  Java  ·  Apache  ·  HIVE
2016-07-23
[Java]Java工程师成神之路
一、基础篇 1.1 JVM 1.1.1. Java内存模型,Java内存管理,Java堆和栈,垃圾回收 http://www.jcp.org/en/jsr/detail?id=133 http://ifeve.com/jmm-faq/ 1.1.2. 了解JVM各种参数及调优 1.1.3. 学习使用Java工具 jps, jstack, jmap, jconsole, jinfo, jhat, javap, … http://kenai.com/projects/btrace http://www.crashub.org/ https://github.com/taobao/TProfiler https://github.com/CSUG/HouseMD http://wiki.cyclopsgroup.org/jmxterm https://github.com/jlusdy/TBJMap 1.1.4. 学习Java诊断工具 http://www.eclipse.org/mat/ http://visualvm.java.net/oqlhelp.html 1.1.5. 自己编写各种outofmemory,stackoverflow程序 HeapOutOfMemory Young OutOfMemory MethodArea OutOfMemory ConstantPool OutOfMemory DirectMemory OutOfMemory Stack OutOfMemory Stack OverFlow 1.1.6. 使用工具尝试解决以下问题,并写下总结 当一个Java程序响应很慢时如何查找问题 当一个Java程序频繁FullGC时如何解决问题,如何查看垃圾回收日志 当一个Java应用发生OutOfMemory时该如何解决,年轻代、年老代、永久代解决办法不同,导致原因也不同 1.1.7. 参考资料 http://docs.oracle.com/javase/specs/jvms/se7/html/ http://www.cs.umd.edu/~pugh/java/memoryModel/ http://gee.cs.oswego.edu/dl/jmm/cookbook.html 1.2. Java基础知识 1.2.1. 阅读源代码 java.lang.String java.lang.Integer java.lang.Long java.lang.Enum java.math.BigDecimal java.lang.ThreadLocal java.lang.ClassLoader & java.net.URLClassLoader java.util.ArrayList & java.util.LinkedList java.util.HashMap & java.util.LinkedHashMap & java.util.TreeMap java.util.HashSet & java.util.LinkedHashSet & java.util.TreeSet 1.2.2. 熟悉Java中各种变量类型 1.2.3. 熟悉Java String的使用,熟悉String的各种函数 1.2.4. 熟悉Java中各种关键字 1.2.5. 学会使用List,Map,Stack,Queue,Set 上述数据结构的遍历 上述数据结构的使用场景 Java实现对Array/List排序 java.uti.Arrays.sort() java.util.Collections.sort() Java实现对List去重 Java实现对List去重,并且需要保留数据原始的出现顺序 Java实现最近最少使用cache,用LinkedHashMap 1.2.6. Java IO&Java NIO,并学会使用 java.io.* java.nio.* nio和reactor设计模式 文件编码,字符集 1.2.7. Java反射与javassist 反射与工厂模式 java.lang.reflect.* 1.2.8. Java序列化 java.io. Serializable 什么是序列化,为什么序列化 序列化与单例模式 google序列化protobuf 1.2.9. 虚引用,弱引用,软引用 java.lang.ref.* 实验这些引用的回收 1.2.10. 熟悉Java系统属性 java.util.Properties 1.2.11. 熟悉Annotation用法 java.lang.annotation.* 1.2.12. JMS javax.jms.* 1.2.13. JMX java.lang.management.* javax.management.* 1.2.14. 泛型和继承,泛型和擦除 1.2.15. 自动拆箱装箱与字节码 1.2.16. 实现Callback 1.2.17. java.lang.Void类使用 1.2.18. Java Agent,premain函数 java.lang.instrument 1.2.19. 单元测试 Junit,http://junit.org/ Jmockit,https://code.google.com/p/jmockit/ djUnit,http://works.dgic.co.jp/djunit/ 1.2.20. Java实现通过正则表达式提取一段文本中的电子邮件,并将@替换为#输出 java.lang.util.regex.* 1.2.21. 学习使用常用的Java工具库 commons.lang, commons.*… guava-libraries netty 1.2.22. 什么是API&SPI http://en.wikipedia.org/wiki/Application_programming_interface http://en.wikipedia.org/wiki/Service_provider_interface 1.2.23. 参考资料 JDK src.zip 源代码 http://openjdk.java.net/ http://commons.apache.org/ https://code.google.com/p/guava-libraries/ http://netty.io/ http://stackoverflow.com/questions/2954372/difference-between-spi-and-api http://stackoverflow.com/questions/11404230/how-to-implement-the-api-spi-pattern-in-java 1.3. Java并发编程 1.3.1. 阅读源代码,并学会使用 java.lang.Thread java.lang.Runnable java.util.concurrent.Callable java.util.concurrent.locks.ReentrantLock java.util.concurrent.locks.ReentrantReadWriteLock java.util.concurrent.atomic.Atomic* java.util.concurrent.Semaphore java.util.concurrent.CountDownLatch java.util.concurrent.CyclicBarrier java.util.concurrent.ConcurrentHashMap java.util.concurrent.Executors 1.3.2. 学习使用线程池,自己设计线程池需要注意什么 1.3.3. 锁 什么是锁,锁的种类有哪些,每种锁有什么特点,适用场景是什么 在并发编程中锁的意义是什么 1.3.4. synchronized的作用是什么,synchronized和lock 1.3.5. sleep和wait 1.3.6. wait和notify 1.3.7. 写一个死锁的程序 1.3.8. 什么是守护线程,守护线程和非守护线程的区别以及用法 1.3.9. volatile关键字的理解 C++ volatile关键字和Java volatile关键字 happens-before语义 编译器指令重排和CPU指令重排 http://en.wikipedia.org/wiki/Memory_ordering http://en.wikipedia.org/wiki/Volatile_variable http://preshing.com/20130702/the-happens-before-relation/ 1.3.10. 以下代码是不是线程安全?为什么?如果为count加上volatile修饰是否能够做到线程安全?你觉得该怎么做是线程安全的? public class Sample { private static int count = 0; public static void increment() { count++; } } 1.3.11. 解释一下下面两段代码的差别 // 代码1 public class Sample { private static int count = 0; synchronized public static void increment() { count++; } } // 代码2 public class Sample { private static AtomicInteger count = new AtomicInteger(0); public static void increment() { count.getAndIncrement(); } } 1.3.12. 参考资料 http://book.douban.com/subject/10484692/ http://www.intel.com/content/www/us/en/processors/architectures-software-developer-manuals.html 二、 进阶篇 2.1. Java底层知识 2.1.1. 学习了解字节码、class文件格式 http://en.wikipedia.org/wiki/Java_class_file http://en.wikipedia.org/wiki/Java_bytecode http://en.wikipedia.org/wiki/Java_bytecode_instruction_listings http://www.csg.ci.i.u-tokyo.ac.jp/~chiba/javassist/ http://asm.ow2.org/ 2.1.2. 写一个程序要求实现javap的功能(手工完成,不借助ASM等工具) 如Java源代码: public static void main(String[] args) { int i = 0; i += 1; i *= 1; System.out.println(i); } 编译后读取class文件输出以下代码: public static void main(java.lang.String[]); Code: Stack=2, Locals=2, Args_size=1 0: iconst_0 1: istore_1 2: iinc 1, 1 5: iload_1 6: iconst_1 7: imul 8: istore_1 9: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream; 12: iload_1 13: invokevirtual #3; //Method java/io/PrintStream.println:(I)V 16: return LineNumberTable: line 4: 0 line 5: 2 line 6: 5 line 7: 9 line 8: 16 2.1.3. CPU缓存,L1,L2,L3和伪共享 http://duartes.org/gustavo/blog/post/intel-cpu-caches/ http://mechanical-sympathy.blogspot.com/2011/07/false-sharing.html 2.1.4. 什么是尾递归 2.1.5. 熟悉位运算 用位运算实现加、减、乘、除、取余 2.1.6. 参考资料 http://book.douban.com/subject/1138768/ http://book.douban.com/subject/6522893/ http://en.wikipedia.org/wiki/Java_class_file http://en.wikipedia.org/wiki/Java_bytecode http://en.wikipedia.org/wiki/Java_bytecode_instruction_listings 2.2. 设计模式 2.2.1. 实现AOP CGLIB和InvocationHandler的区别 http://cglib.sourceforge.net/ 动态代理模式 Javassist实现AOP http://www.csg.ci.i.u-tokyo.ac.jp/~chiba/javassist/ ASM实现AOP http://asm.ow2.org/ 2.2.2. 使用模板方法设计模式和策略设计模式实现IOC 2.2.3. 不用synchronized和lock,实现线程安全的单例模式 2.2.4. nio和reactor设计模式 2.2.5. 参考资料 http://asm.ow2.org/ http://cglib.sourceforge.net/ http://www.javassist.org/ 2.3. 网络编程知识 2.3.1. Java RMI,Socket,HttpClient 2.3.2. 用Java写一个简单的静态文件的HTTP服务器 实现客户端缓存功能,支持返回304 实现可并发下载一个文件 使用线程池处理客户端请求 使用nio处理客户端请求 支持简单的rewrite规则 上述功能在实现的时候需要满足“开闭原则” 2.3.3. 了解nginx和apache服务器的特性并搭建一个对应的服务器 http://nginx.org/ http://httpd.apache.org/ 2.3.4. 用Java实现FTP、SMTP协议 2.3.5. 什么是CDN?如果实现?DNS起到什么作用? 搭建一个DNS服务器 搭建一个 Squid 或 Apache Traffic Server 服务器 http://www.squid-cache.org/ http://trafficserver.apache.org/ http://en.wikipedia.org/wiki/Domain_Name_System 2.3.6. 参考资料 http://www.ietf.org/rfc/rfc2616.txt http://tools.ietf.org/rfc/rfc5321.txt http://en.wikipedia.org/wiki/Open/closed_principle 2.4. 框架知识 spring,spring mvc,阅读主要源码 ibatis,阅读主要源码 用spring和ibatis搭建java server 2.5. 应用服务器知识 熟悉使用jboss,https://www.jboss.org/overview/ 熟悉使用tomcat,http://tomcat.apache.org/ 熟悉使用jetty,http://www.eclipse.org/jetty/ 三、 高级篇 3.1. 编译原理知识 3.1.1. 用Java实现以下表达式解析并返回结果(语法和Oracle中的select sysdate-1 from dual类似) sysdate sysdate - 1 sysdate - 1/24 sysdate - 1/(12*2) 3.1.2. 实现对一个List通过DSL筛选 QList<Map<String, Object>> mapList = new QList<Map<String, Object>>; mapList.add({"name": "hatter test"}); mapList.add({"id": -1,"name": "hatter test"}); mapList.add({"id": 0, "name": "hatter test"}); mapList.add({"id": 1, "name": "test test"}); mapList.add({"id": 2, "name": "hatter test"}); mapList.add({"id": 3, "name": "test hatter"}); mapList.query("id is not null and id > 0 and name like '%hatter%'"); 要求返回列表中匹配的对象,即最后两个对象; 3.1.3. 用Java实现以下程序(语法和变量作用域处理都和JavaScript类似): 代码: var a = 1; var b = 2; var c = function() { var a = 3; println(a); println(b); }; c(); println(a); println(b); 输出: 3 2 1 2 3.1.4. 参考资料 http://en.wikipedia.org/wiki/Abstract_syntax_tree https://javacc.java.net/ http://www.antlr.org/ 3.2. 操作系统知识 Ubuntu Centos 使用linux,熟悉shell脚本 3.3. 数据存储知识 3.3.1. 关系型数据库 MySQL 如何看执行计划 如何搭建MySQL主备 binlog是什么 Derby,H2,PostgreSQL SQLite 3.3.2. NoSQL Cache Redis Memcached Leveldb Bigtable HBase Cassandra Mongodb 图数据库 neo4j 3.3.3. 参考资料 http://db-engines.com/en/ranking http://redis.io/ https://code.google.com/p/leveldb/ http://hbase.apache.org/ http://cassandra.apache.org/ http://www.mongodb.org/ http://www.neo4j.org/ 3.4. 大数据知识 3.4.1. Zookeeper,在linux上部署zk 3.4.2. Solr,Lucene,ElasticSearch 在linux上部署solr,solrcloud,,新增、删除、查询索引 3.4.3. Storm,流式计算,了解Spark,S4 在linux上部署storm,用zookeeper做协调,运行storm hello world,local和remote模式运行调试storm topology。 3.4.4. Hadoop,离线计算 Hdfs:部署NameNode,SecondaryNameNode,DataNode,上传文件、打开文件、更改文件、删除文件 MapReduce:部署JobTracker,TaskTracker,编写mr job Hive:部署hive,书写hive sql,得到结果 Presto:类hive,不过比hive快,非常值得学习 3.4.5. 分布式日志收集flume,kafka,logstash 3.4.6. 数据挖掘,mahout 3.4.7. 参考资料 http://zookeeper.apache.org/ https://lucene.apache.org/solr/ https://github.com/nathanmarz/storm/wiki http://hadoop.apache.org/ http://prestodb.io/ http://flume.apache.org/,http://logstash.net/,http://kafka.apache.org/ http://mahout.apache.org/ 3.5. 网络安全知识 3.5.1. 什么是DES、AES 3.5.2. 什么是RSA、DSA 3.5.3. 什么是MD5,SHA1 3.5.4. 什么是SSL、TLS,为什么HTTPS相对比较安全 3.5.5. 什么是中间人攻击、如果避免中间人攻击 3.5.6. 什么是DOS、DDOS、CC攻击 3.5.7. 什么是CSRF攻击 3.5.8. 什么是CSS攻击 3.5.9. 什么是SQL注入攻击 3.5.10. 什么是Hash碰撞拒绝服务攻击 3.5.11. 了解并学习下面几种增强安全的技术 http://www.openauthentication.org/ HOTP http://www.ietf.org/rfc/rfc4226.txt TOTP http://tools.ietf.org/rfc/rfc6238.txt OCRA http://tools.ietf.org/rfc/rfc6287.txt http://en.wikipedia.org/wiki/Salt_(cryptography) 3.5.12. 用openssl签一个证书部署到apache或nginx 3.5.13. 参考资料 http://en.wikipedia.org/wiki/Cryptographic_hash_function http://en.wikipedia.org/wiki/Block_cipher http://en.wikipedia.org/wiki/Public-key_cryptography http://en.wikipedia.org/wiki/Transport_Layer_Security http://www.openssl.org/ https://code.google.com/p/google-authenticator/ 四、 扩展篇 4.1. 相关知识 4.1.1. 云计算,分布式,高可用,可扩展 4.1.2. 虚拟化 https://linuxcontainers.org/ http://www.linux-kvm.org/page/Main_Page http://www.xenproject.org/ https://www.docker.io/ 4.1.3. 监控 http://www.nagios.org/ http://ganglia.info/ 4.1.4. 负载均衡 http://www.linuxvirtualserver.org/ 4.1.5. 学习使用git https://github.com/ https://git.oschina.net/ 4.1.6. 学习使用maven http://maven.apache.org/ 4.1.7. 学习使用gradle http://www.gradle.org/ 4.1.8. 学习一个小语种语言 Groovy Scala LISP, Common LISP, Schema, Clojure R Julia Lua Ruby 4.1.9. 尝试了解编码的本质 了解以下概念 ASCII, ISO-8859-1 GB2312, GBK, GB18030 Unicode, UTF-8 不使用 String.getBytes() 等其他工具类/函数完成下面功能 public static void main(String[] args) throws IOException { String str = "Hello, 我们是中国人。"; byte[] utf8Bytes = toUTF8Bytes(str); FileOutputStream fos = new FileOutputStream("f.txt"); fos.write(utf8Bytes); fos.close(); } public static byte[] toUTF8Bytes(String str) { return null; // TODO } 想一下上面的程序能不能写一个转GBK的? 写个程序自动判断一个文件是哪种编码 4.1.10. 尝试了解时间的本质 时区 & 冬令时、夏令时 http://en.wikipedia.org/wiki/Time_zone ftp://ftp.iana.org/tz/data/asia http://zh.wikipedia.org/wiki/%E4%B8%AD%E5%9C%8B%E6%99%82%E5%8D%80 闰年 http://en.wikipedia.org/wiki/Leap_year 闰秒 ftp://ftp.iana.org/tz/data/leapseconds System.currentTimeMillis() 返回的时间是什么 4.1.11. 参考资料 http://git-scm.com/ http://en.wikipedia.org/wiki/UTF-8 http://www.iana.org/time-zones 4.2. 扩展学习 4.2.1. JavaScript知识 4.2.1.1. 什么是prototype 修改代码,使程序输出“1 3 5”: http://jsfiddle.net/Ts7Fk/ 4.2.1.2. 什么是闭包 看一下这段代码,并解释一下为什么按Button1时没有alert出“This is button: 1”,如何修改: http://jsfiddle.net/FDPj3/1/ 4.2.1.3. 了解并学习一个JS框架 jQuery ExtJS ArgularJS 4.2.1.4. 写一个Greasemonkey插件 http://en.wikipedia.org/wiki/Greasemonkey 4.2.1.5. 学习node.js http://nodejs.org/ 4.2.2. 学习html5 ArgularJS,https://docs.angularjs.org/api 4.2.3. 参考资料 http://www.ecmascript.org/ http://jsfiddle.net/ http://jsbin.com/ http://runjs.cn/ http://userscripts.org/ 五、 推荐书籍 《深入Java虚拟机》 《深入理解Java虚拟机》 《Effective Java》 《七周七语言》 《七周七数据》 《Hadoop技术内幕》 《Hbase In Action》 《Mahout In Action》 《这就是搜索引擎》 《Solr In Action》 《深入分析Java Web技术内幕》 《大型网站技术架构》 《高性能MySQL》 《算法导论》 《计算机程序设计艺术》 《代码大全》 《JavaScript权威指南》  
文章
SQL  ·  安全  ·  Java  ·  HIVE  ·  流计算
2015-12-23
开发与运维
5193 人关注 | 125225 讨论 | 184493 内容
+ 订阅
  • 小知识随手记:MD5加密与SHA-1加密
  • 【Kotlin 初学者】数
  • 小工具随手记:Windows下安装Git并clone一个项目
查看更多 >
安全
1033 人关注 | 23271 讨论 | 52013 内容
+ 订阅
  • 小知识随手记:MD5加密与SHA-1加密
  • 【Kotlin 初学者】数
  • Linux学习笔记 1(Linux安装)
查看更多 >
大数据
183983 人关注 | 22887 讨论 | 51527 内容
+ 订阅
  • 秒懂流媒体协议 RTMP 与 RTSP
  • 笔记:python字典基础随手记
  • SpringBoot快速搭建、自动流程进阶、装配机制、功能扩展点详解
查看更多 >
数据库
248795 人关注 | 44342 讨论 | 55620 内容
+ 订阅
  • 小知识随手记:MD5加密与SHA-1加密
  • 小知识随手记:使用Navicat进行数据库表设计
  • 呕心沥血写了三天3两夜24k字的MySQL详细教程(三)
查看更多 >
微服务
22761 人关注 | 9846 讨论 | 19666 内容
+ 订阅
  • 在Centos 7上配置Pouch 镜像方法
  • centos7 安装Redis
  • SpringBoot快速搭建、自动流程进阶、装配机制、功能扩展点详解
查看更多 >