• Angualar:指令大全


    指令:


    • 内置渲染指令
    • 内置事件指令
    • 内置节点指令
    • 自定义指令
      • restrict template replace属性
      • templateUrl属性
      • trnsclude priorty terminal属性
      • compile link属性
      • controller aontrollAs属性
      • require属性
      • scope属性
    • 自定义:demo

    定义方式:


    • 模块注入$compileProvider
    angular.module('keApp', [], ['$compileProvider', function(com) {//看到这种方式的好处:$compileProvider==com,压缩代码的时候,不用担心变量会被替换的问题
    	com.directive("keNodeMap", function() {
    		return {
    			restrict: "ECAM",
    			template: '<div>内容11</div>',
    			replace: true
    		}
    	})
    }])
    
    • 普通的指令
    angular.module('keApp', [])
    	.directive("keNodeMap", function() {
    		return {
    			restrict: "ECAM",
    			templateUrl: 'tpls/tpl1.htm',
    			replace: true
    		}
    	})
    
    • 隐式注入
    app.directive('myDirective', function ($injector) {
      return function () {
        console.log('postLink2: ', $injector);
      }
    });
    
    • 显式注入
    app.directive('myDirective', ['$injector', function ($injector) {
      return function () {
        console.log('postLink3: ', $injector);
      }
    }]);
    

    自定义指令中属性及参数记录


    var myModule = angular.module(...);
         myModule.directive('directiveName', 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,//true,{@ = &}
            controller: function($scope, $element, $attrs, $transclude, otherInjectables) { ... },// $transclude, otherInjectables
            require: 'siblingDirectiveName', // or // ['^parentDirectiveName', '?optionalDirectiveName', '?^optionalParent'],
            compile: function compile(tElement, tAttrs, transclude) { //transclude //没有scope,
              return {
                pre: function preLink(scope, iElement, iAttrs, controller) { ... }, //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;
        });
    

    contoller compile link 执行顺序

    <!DOCTYPE html>
    <html>
    <head>
    
      <meta charset="utf-8">
      <meta name="viewport" content="width=device-width">
      <title>JS Bin</title>
      <script src="ddd/angular.js"></script>
      <script>
      angular.module('modul',[]).
      directive('stringAdd', function() {  
        return {  
            restrict: 'E',  
            template: '<p>顺序:{{number}}!</p>',  
            transclude:true,
    
            controller: function($scope, $element, $attrs, $transclude){  //otherInjectables
                $scope.number = $scope.number + "2, ";  
                console.log($element.prop("outerHTML"));
                console.log($attrs);
                console.log($transclude);//$transclude是一个函数
            },  
            
            // controller: ['$scope',function(sco){  //没找到$element, $attrs, $transclude的provider
            //     sco.number = sco.number + "2, ";  
            //     }],
            //controllerAs:'myController',  
            link: function(scope, el, attrs) { 
                 // controller  其他控制器  包括AB指令之间交互的 A的conntroller起别名A的conntrollerAs B有require之后,B的link可以注入 ,,估计B的controller也可以  B的compile也可以
                //不需要写$开头
                scope.number = scope.number + "3,";  
            },  
            compile: function(element, attributes) {  // transclude
                return {  
                    pre: function preLink(scope, element, attributes) {  
                        scope.number = scope.number + "4, ";  
                    },  
                    post: function postLink(scope, element, attributes) {  
                        scope.number = scope.number + "5 ";  
                    }  
                };  
            }  
        }  
    })
      .controller('ctrl',['$scope',  
        function($scope) {  
            $scope.number = '1, ';  
        }  
    ]); 
        </script>
    </head>
    
    <body ng-app="modul">  
        <div ng-controller="ctrl">  
            <string-add>trnsclate</string-add>  
        </div>  
    </body>  
    
    </html>
    

    结果

    图:

    1,restrict template replace属性


    <div ng-app="keApp">
    		<ke-node-map></ke-node-map>
    		<div class="ke-node-map"></div>
    		<div ke-node-map=''></div>
    		<!-- directive: ke-node-map -->
    	</div>
    
    angular.module('keApp', [], ['$compileProvider', function(com) {
    	com.directive("keNodeMap", function() {//js中写的按照camel法则写,html中要转成小写,并在变小写的字母前加上-
    		return {//这样指令返回一段什么样的html
    			//e代表替换ke-node-map标签中的内容,C代表替换class=‘ke-node-map’的标签的内容
    			//A代表替换有ke-node-map=‘’属性的标签的内容,M代表替换 <!-- directive:ke-node-map -->(记得有空格)
    			restrict: "ECAM",
    			template: '<div>内容11</div>',//这个模板必须加标签包围,如果去掉,就报错
    			replace: true//表示具有restrict: "ECAM",代表的标签和内容全部替换成template。这里提醒,没这个属性,原来html标签不会去掉,只是内容替换了。
    		}
    	})
    }])
    
    

    结果

    2,templateUrl属性


    1,第一种模板方式


    在项目在添加一个放模板的文件夹,添加模板(一个不带html、head、body,只有一般的div等平常标签文件)

    tpls/tpl1.htm

    <div>我是一个被加载进来的模板,我没html,body,外面必须有标签包围</div>
    

    html同上

    js

    angular.module('keApp', [])
    	.directive("keNodeMap", function() {
    		return {
    			restrict: "ECAM",
    			templateUrl: 'tpls/tpl1.htm',
    			replace: true
    		}
    	})
    
    

    FireFox结果


    google结果 报错了!

    主要错误:Cross origin requests are only supported for protocol schemes: http, data, chrome, chrome-extension, https, chrome-extension-resource.

    这个问题原因:google浏览器不然访问本地html文件(url中以‘file://..开头’),被认定为跨域问题,我们称这个为同源策略:这个问题会阻止chrome从url中为file://..中加载模板,并显示一个“Access-Controll-Allow-Origin”不允许源为null。

    解决方式

    1,让chrome的url以Locolhost://..开头的路径访问。也就是把项目放在服务器上加载
    2,如果非要chrome的url以一‘file://..’形式访问,我们给chrome设置一个标志,命令为:chrome -allow-file-access-from-files,这样命令之后,chrome会新打开一个(也许之前你手动打开过),我们只能把url以‘file://..’开头的放进这个新打开的chrome中,才不会报错。放在原来打开的chrome,依然会报错。
    参考地址
    https://stackoverflow.com/questions/10752055/cross-origin-requests-are-only-supported-for-http-error-when-loading-a-local/23758738#23758738

    操作截图

    1,找到chrome的安装路径:‘打开文件位置’

    2,打开cmd:输入cd 路径 ,记得不要找到chrome.exe,而是找到chrome.exe所在的目录,我输入的是cd C:Program FilesGoogleChromeApplication
    3,之后cmd会转到这个文件夹下,继续输入chrome --allow-file-access-from-files
    4,这个时候,会自动打开一个新chrome(不管你原来打开没打开chrome)
    5,在这个新打开的chrome里面输入以'file://..'开头的路径,便可以访问了。原来打开的chrome还是不能。


    2,第二种模板


    这种方式,不用新建模板文件了,而是把模板内容放在页面。
    <script type="text/ng-template" id="keTpl">模板内容</script>。
    这个标签必须放到ng-app内,id为js中templateUrl的值。
    

    html

    <div ng-app="keApp">
    	<script type="text/ng-template" id="keTpl">
    		<div>页面内部的text/template</div>
    	</script>
    		<ke-node-map>dd</ke-node-map>
    		<div class="ke-node-map">s</div>
    		<div ke-node-map=''>s</div>
    		<!-- directive: ke-node-map -->
    	</div>
    

    js

    angular.module('keApp', [])
    	.directive("keNodeMap", function() {
    		return {
    			restrict: "ECAM",
    			templateUrl: 'keTpl',
    			replace: true
    		}
    	})
    

    结果

    3,不论哪种模板,都能放表达式和指令,这里拿{{}}和ng-model来试验

    注意不管哪种模板,必须要有而且仅有一个rootelement根节点包围,否则会报错

    Template for directive must have exactly one root element
    参考地址:http://stackoverflow.com/questions/27992470/template-for-directive-must-have-exactly-one-root-element

    模板

    <div>
    	<div>我是一个被加载进来的模板,我没html,body,外面必须有必须有而且仅一个rootelement根节点包围
    	</div>
    	<input ng-model="parm3"/>
    </div>
    

    html

    <div ng-app="keApp">
    		<script type="text/ng-template" id="keTpl">
    		<div>
    			<div>页面内部的text/template,必须有一个rootelement根节点包围</div>
    			<input ng-model="parm1"/>		
    			{{parm2}}
    		</div>
    	</script>
    		<div ng-controller="ctrKe">
    			<ke-node-map></ke-node-map>
    			<div class="ke-node-map"></div>
    			<div ke-node-map=''></div>
    			<!-- directive: ke-node-map -->
    
    			<ke-node-mapt></ke-node-mapt>
    			<div class="ke-node-mapt"></div>
    			<div ke-node-mapt=''></div>
    			<!-- directive: ke-node-mapt -->
    		</div>
    	</div>
    

    js

    angular.module('keApp', [])
    	.directive("keNodeMap", function() {
    		return {
    			restrict: "ECAM",
    			templateUrl: 'keTpl',
    			replace: true
    		}
    	})
    	.directive("keNodeMapt", function() {
    		return {
    			restrict: "ECAM",
    			templateUrl: 'tpls/tpl1.htm',
    			replace: true
    		}
    	})
    	.controller('ctrKe', ['$scope', function($scope){
    		$scope.parm1 = "aaa";
    		$scope.parm2 = "bbb";
    		$scope.parm3 = "ccc";
    		
    	}])
    	// .controller('ctrKe', function($scope) {
    	// 	$scope.parm1 = "aaa";
    	// 	$scope.parm2 = "bbb";
    	// 	$scope.parm3 = "ccc";
    	// })
    

    结果不要忘了,在chrome中要cmd开启新的chrome哦


    3,trnsclude priorty terminal属性


    1,transclude:true 将view中的自定义指令的内容(包括包含的节点)保存下来,在js中的template属性中,加上具有ng-transclude属性的标签(这个标签的内容有无都不显示)

    <div ng-app="keApp">
    		<ke-node-map><div ng-class='old'>保留的老标签+老内容到transclude内1</div></ke-node-map>
    		<!-- <div class="ke-node-map"><div ng-class='old'>保留老标签+老内容到transclude内2</div></div>
    		<div ke-node-map=''><div ng-class='old'>保留老标签+老内容到transclude内3</div></div> -->
    	</div>
    
    angular.module('keApp', [])
    	.directive("keNodeMap", function() {
    		return {
    			restrict: "ECAM",
    			template: '<div>模板的transclude兄弟的内容<div ng-transclude></div> </div>',
    			replace: true,
    			transclude: true
    		}
    	})
    
    

    截图



    2,priorty terminal,这两个属性都是解决多个指令在一起的时候执行优先级(顺序)的问题

    在内置指令中:
    加入有<li ng-repeat="item in set" ng-click=""></li>在这个创建dom的过程中,是先ng-repeat,然后再ng-click,这几个指令肯定有一定的执行的优先级。
    在自定义指令中如何表示呢?这就使用到了priorty terminal属性。
    下面看

    <div ng-app="keApp">
    	<div class="ke-node-map ke-node-mapt">
    		<div ng-class='old'>原始数据</div>
    	</div>
    	<!-- 
    		<div ke-node-map ke-node-mapt>
    		<div ng-class='old'>原始数据</div>
    		</div>
    	-->
    </div>
    
    angular.module('keApp', [])
    	.directive("keNodeMap", function() {
    		return {
    			restrict: "CA",
    			template: '<div>新数据1<div ng-transclude></div> </div>',//待会要注释掉
    			replace: true,//待会要注释掉
    			priority: 3  
    		}
    	})
    	.directive("keNodeMapt", function() {
    		return {
    			restrict: "CA",
    			template: '<div>新数据2 </div>',
    			replace: true,
    			priority: 4
                            //terminal:true
    		}
    	})
    

    结果:

    现象和解释:

    priority越大的越先执行,ng-repeat默认priority为1000。默认的自定义指令priority都是0,先定义哪个,哪个指令先执行。
    当替换模板的时候,优先级为4的指令先正确执行,然后执行优先级为3的指令,但是优先级为3的是替换模板指令就出错了。因为已经“替换了”,再替换报错,就正常了。
    [$compile:multidir] Multiple directives [keNodeMapt, keNodeMap] asking for template on: <div class="ke-node-map ke-node-mapt">
    如果把template: '<div>新数据1<div ng-transclude></div> </div>',replace: true,注释掉,就不报错了。

    我们想让优先级为4的执行完,优先级小于4的都不执行的话,我们只需在优先级为4的指令上加一个属性terminal:true,终止优先级比自己低的执行。

    4,compile link属性


    以上自定义指令:都是为了实现渲染指令的作用。那我们为一些改变DOM结构绑定事件改变样式等功能,就接着往下看。
    为了一些兼容性问题,最好我们定义restrict为C,A的指令`
    compile属性本质调用link属性。

    1,compile属性:方法内直接返回一个函数,就是link属性对应的方法。也就是对应的Link阶段。这样就不用再写link属性了。
    2,compile属性:方法内返回一个对象,{pre:function preLink(){},post:function postLink(){}},返回这样的post属性对应的函数就是Link函数。
    3,compile属性:方法内改变DOM,在上面解释多指令不能用多个模板改变标签的时候,我们可以在copile属性内改变,达到'类似多模板'的功能,操作DOM。
    这个时候,单独写link属性,来改变样式,绑定事件。
    注意:
    在compile执行之前,如果有渲染模板,模板文件都已经加到页面了。如果没有模板,我们可以通过compile的element属性改变,实现“有模板”的功能。
    一般:我们在compile属性内“改变标签结构”,比如添加节点什么的,类似实现“不能多模板”的功能。这个有优先级的执行顺序限制!!
    一般:在Link属性中,我们“改变样式”,“绑定事件”。这个没有优先级的执行顺序限制!!

    例子1


    View

    <!DOCTYPE html>
    <html lang = "zh-CN">
    <head>
    	<meta charset="utf-8"></meta>
    <script src="ddd/angular.js"></script>
    <script  src="customdirective6.js"></script>
    <style type="text/css">
    	.divDemo{
    		border: 1px solid red;
    		background: blue;
    	}
    </style>
    </head>
    </head>
    <body>
    <div ng-app="keApp">
    	<div ng-controller="keCtr1" >
    		<div class="ke-node-map ke-node-mapt">{{name}}</div>
    	</div>
    </div>
    </body>
    </html>
    

    js

    angular.module('keApp', [])
    	.directive("keNodeMap", function() {
    		return {
    			restrict: "CA",
    			//template: '<div>{{name}}</div>',//[$compile:multidir] Multiple directives [keNodeMapt, keNodeMap] asking for template on: <div class="ke-node-map ke-node-mapt">
    			priority: 3,
    			compile: function(element, attr, transclude ) {
    				element.append(angular.element('<div>{{name}}</div>'))
    				console.log('1编译阶段:keNodeMap指令优先级低,现在不能再访问新模板修改,这是时候更改原始标签,用jqlite:element.append(angular.element(<div>{{name}}</div>div>))', element.prop('outerHTML'))
    				return function(scope, elements, attrs, contrs) {
    					console.log('1postLink就是link属性,多个指令的link并不按priority大小执行,哪个指令先定义,那么这个指令的link先执行。一般在link内一般“改变样式”,“绑定事件”', element.prop('outerHTML'))
    					element.bind('click',function(e) {
    						element.addClass('divDemo')
    						console.log('点击了1')
    					})
    				}
    			}
    		}
    	})
    	.directive("keNodeMapt", function() {
    		return {
    			restrict: "CA",
    			template: '<div>新数据2 <div ng-transclude>{{name}}</div></div>',
    			replace: true,
    			transclude: true,
    			priority: 4,
    			compile: function(element, attr, contr) {
    				console.log('2编译阶段:keNodeMapt指令优先级高,先transclude好(相当与在编译阶段改变原始标签,用jqlite:element.append(angular.element(<div>{{name}}</div>div>)))', element.prop('outerHTML'))
    				return function(scope, elements, attrs, contrs) {
    					console.log('2postLink就是link属性,多个指令的link并不按priority大小执行,哪个指令先定义,那么这个指令的link先执行。一般在link内一般“改变样式”,“绑定事件”', element.prop('outerHTML'))
    					element.bind('click',function(e) {
    						console.log('点击了2')
    					})
    				}
    			}
    		}
    	})
    	.controller('keCtr1', ['$scope', function(s) {
    		s.name = '李可'
    	}])
    

    截图 多注意我的标记,以及打印信息


    例子2 ng-repeat的联合使用


    view

    <div ng-app="keApp">
        <div ng-controller="firstController">
            <!--
                1. div 转换为dom结构
                2. 默认的优先级为0,哪个先定义哪个先使用
            -->
            <div ng-repeat="user in users" custom-tags="" custom-tags2>
            </div>
        </div>
    </div>
    

    js

    //var i = 0;
    var myApp = angular.module('keApp', [])
    .directive('customTags', function() {
        return {
            restrict: 'ECAM',
            template: '<div>{{user.name}}</div>',
            replace: true,
            priority: 5,
            compile: function(ele, attr, transclude) {
                // 编译阶段...
                console.log('customTags编译阶段...');
                console.log('1继续改变标签前', ele.prop("outerHTML"));
                ele.append(angular.element('<div>{{user.name}}{{user.count}}</div>'));
                console.log('1继续改变标签后', ele.prop("outerHTML"));
                return {
                    // 表示在编译阶段之后,指令连接到子元素之前运行
                    pre: function preLink(scope, ele, attr, controller) {
                       // console.log('1prescope', scope)
                        console.log('1prehtml', ele.prop("outerHTML"))
                    },
                    // 表示在所有子元素指令都连接之后才运行
                    post: function postLink(scope, ele, attr, controller) {
                       // console.log('1postscope', scope);
                        console.log('1posthtml', ele.prop("outerHTML"))
                        // ele.on('click', function() {
                        //     scope.$apply(function() {
                        //         scope.user.name = 'click after';
                        //         scope.user.count = ++i;
                        //         // 进行一次 脏检查
                        //     });
                        // })
                    }
                }
                // 可以直接返回 postLink
                // return function(){
                // console.log('compile return fun');
                //}
            },
            // 此link表示的就是 postLink
            // link: function() {
            //     //                iElement.on('click',function(){
            //     //                    scope.$apply(function(){
            //     //                        scope.user.name = 'click after';
            //     //                        scope.user.count = ++i;
            //     //                        // 进行一次 脏检查
            //     //                    });
            //     //                })
            // }
        }
    })
    .directive('customTags2', function() {
        return {
            restrict: 'ECAM',
            replace: true,
            priority: 6,
            compile: function(ele, tAttrs, transclude) {
                // 编译阶段...
                console.log('customTags2编译阶段...');
                console.log('2改变标签前', ele.prop("outerHTML"));
                ele.append(angular.element('<span>{{user.name}}{{user.count}}</span>'));
                console.log('2改变标签后', ele.prop("outerHTML"));
                return {
                    // 表示在编译阶段之后,指令连接到子元素之前运行
                    pre: function preLink(scope, ele, attr, controller) {
                        //console.log('2prescope', scope)
                        console.log('2prehtml', ele.prop("outerHTML"))
                    },
                    // 表示在所有子元素指令都连接之后才运行
                    post: function postLink(scope, ele, attr, controller) {
                       // console.log('2postscope', scope);
                        console.log('2posthtml', ele.prop("outerHTML"))
                    }
                }
            }
        }
    })
    .controller('firstController', ['$scope', function($scope) {
        $scope.users = [{
            id: 10,
            name: '张三'
        }, {
            id: 20,
            name: '李四'
        }];
    }]);
    

    截图


    controller controllerAs require属性

    scope属性


    为了弄懂scope属性的绑定策略@,&,=两边的变量代表的对象是什么,请按照以下步骤。

    scope属性的前身今世:link属性

    <script>
    angular.module('app', [])
     .controller("keController",function($scope){
              $scope.Name="李可"; 
            })
            .directive("direct",function(){
                    return{
                        restrict: 'E',
                        template: '<div>指令作用域访问到controller作用域中变量:{{ parentName }}</div>' ,
    	       link:function(direcScope,eles,attrs,con){   
    	      	 //	有这个方法可以知道,在指令调用中使用attrs.forName之前,他已经被控制器赋值上了。已经给了看attrs的调试方法,
    		// 	angular.forEach(attrs,function(data,index,array){
    		// 	console.log(index+':',attrs[index]);
    		// })
    		direcScope.parentName=attrs.forName;
                        }
                     } 
              })
    </script>
    </head>
    <body>
    <div ng-app="app">
    	<div ng-controller="keController">
    		<direct for-name="{{Name}}"></direct><!--在指令调用中使用attrs.forName之前,他已经被控制器赋值上了。 -->
    	</div>
    </div>
    

    截图

    上述功能实现了指令作用域访问控制器作用域的变量“字符串”。很多都写在link属性中,但是link主要为绑定事件 添加样式功能的,而且写的也多。有一个更为方便的方式,那就是scope属性。
    代码

    <script>
    angular.module('app', [])
     .controller("keController",function($scope){
              $scope.Name="李可"; 
            })
            .directive("direct",function(){
                    return{
                        restrict: 'E',
                        template: '<div>指令作用域访问到controller作用域中变量:{{ parentName }}</div>' ,
                        scope:{ 
                        	//为了简化link的写法,我们引入scope属性(对比着link属性看)
                        	//第一个变量就是指令scope的变量,
                        	//第二个变量就是attrs的一个属性,指令<direct for-name="{{Name}}"></direct>中的forName属性,通过驼峰法则找到for-name
                        	parentName:'@forName'
                        }
    	 //       link:function(direcScope,eles,attrs,con){   
    		// direcScope.parentName=attrs.forName;
      	//      }
                     } 
              })
    </script>
    </head>
    <body>
    <div ng-app="app">
    	<div ng-controller="keController">
    		<direct for-name="{{Name}}"></direct><!--在指令调用中使用attrs.forName之前,他已经被控制器赋值上了。 -->
    	</div>
    </div>
    </body>
    

    简写

    =,&使用

    dodirfun({param:txtContent })传参的时候拼接一个json对象。txtContent正是文本框的ng-model;

    <!doctype html>
    <html >
    <head>
    <meta charset="utf-8 "></meta>
    <script src="https://rawgit.com/angular/bower-angular/master/angular.min.js"></script>
    <script>
    angular.module('app', [])
     .controller("keController",function($scope){
              $scope.Name="名字"; 
               $scope.dofun=function(param){
    		alert('左侧内容:'+param);
               }
            })
            .directive("direct",function(){
                    return{
                        restrict: 'E',
                        template: '<div><input type="text" ng-model="dirName"></div>' ,
                        scope:{ 
                        	//forName:'=forName'
                        	//forName:'='//根据上面讲的,你应该知道什么时候这么写
                        	dirName:"=forName"
                        }
                     } 
              })
            .directive("fun",function(){
                    return{
                        restrict: 'E',
                        template: '<div><input type="text" ng-model="txtContent">'+
                        		      '<input type="button" value="点击" ng-click="dodirfun({param:txtContent })"></div>' ,
                        scope:{ 
                        	dodirfun:"&funattr"
                        	// funattr:"&funattr"//根据上面讲的,你应该知道什么时候这么写
                        	// funattr:"&"
                        }
                     } 
              })
    </script>
    </head>
    <body>
    <div ng-app="app">
    	<div ng-controller="keController">
    		<input type="text" ng-model="Name">
    		<direct for-name="Name"></direct><!--绑定策略为=时,此处千万不要加{{}},此处需要expression表达式-->
    		<fun funattr="dofun(param)"></fun><!--绑定策略为&时,形参和实参最好写一样,要不容易-->
    		<fun funattr="dofun(param)"></fun>
    	</div>
    </div>
    </body>
    </html>
    
  • 相关阅读:
    旁友数独会伐啦?python秒解数独了解下伐啦?
    趁老王不在,和隔壁邻居斗斗地主,比比大小
    ll字段 详解 文件权限
    etc/pass命令列表
    maven配置
    linux常用汇总
    Tomcat学习笔记
    JavaEE高级-Hibernate学习笔记
    JavaEE高级-通用Mapper学习笔记
    jQueryrocket
  • 原文地址:https://www.cnblogs.com/leee/p/5443715.html
Copyright © 2020-2023  润新知