#
1、<script language="javascript">
window.onbeforeunload = function()
{
if(((event.clientX > document.body.clientWidth - 43) && (event.clientY < 23)) || event.altKey) {
window.event.returnValue = '关闭。';
}
}
</script>
2、<script language="javascript">
window.onbeforeunload = function()
{
var n = window.event.screenX - window.screenLeft;
var b = n > document.documentElement.scrollWidth-20;
if(b && window.event.clientY < 0 || window.event.altKey)
{
alert("是关闭而非刷新");
window.open(this.location);
//return false;
//window.event.returnValue = ""; }
}
</script>
本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/ajaxchen_615/archive/2009/07/06/4325917.aspx
如果你的页面对IE7兼容没有问题,又不想大量修改现有代码,同时又能在IE8中正常使用,微软声称,开发商仅需要在目前兼容IE7的网站上添加一行代码即可解决问题,此代码如下:
CODE:
<meta http-equiv="x-ua-compatible" content="ie=7" />
从今天开始学习.net开发,java开发工作暂放一放,不过在学习.net的过程中,会结合java对比,在学习新知识的同时也巩固和复习一下java的知识,在学习中提升,在学习中成长,加油!
1.对象和属性
对象是一种复核数据类型,它们将多个数据值几种在一个单元中,而且允许使用名字来存取这些值,即对象是一个无序的属性集合,这个属性都有自己的名字和值,存储在对象中的以命名的值可以是数字和字符串这样的原始值,也可以是对象。
2.对象的创建
对象是由运算符new来创建的,在这个运算符之后必须有用于初始化对象的构造函数名。
创建一个空对象(即没有属性的对象)
var o = new Object();
js还支持内部构造函数,它们以另一种简洁的方式初始化新创建的对象
var now = new Date();
var new_year = new Date(2009,09,19);
3.属性的设置和查询
4.属性的枚举
for/in循环列出的属性并没有特定顺序,而且它只能枚举出所有用户定义的属性,但是却不能枚举出那些预定义的属性或方法,并且它可以
枚举出被设为undefined的属性,但是它不能列出被delete删除的属性。
5.未定义的属性
如果要读取一个不存在属性的值,那么得到的结果是一个特殊的js值,undefined
可以使用delete来删除一个对象的属性,注意:删除一个属性并不仅仅是把该属性设置为undefined,而是真正从对象中移除了该属性。
6.构造函数
它由new运算符调用,传递给它的是一个新创建的空对象引用,将该引用作为关键字this的值,而且它还要对新创建的对象进行适当的初始化。
注意:构造函数如何使用它的参数来初始化this关键字所引用的对象的属性,记住,构造函数只是初始化了特定的对象,但并不返回这个对象。
构造函数通常没有返回值,他们只是初始化由this值传递进来的对象,并且什么也不返回..但是,构造函数可以返回一个对象值,如果这样做,被返回的对象就成了new表达式的值了,在这种情况下,
this值所引用的对象就被丢弃了。
7.方法
方法有一个非常重要的属性,即在方法主体内部,关键字this的值变成了调用该方法的对象。
方法和函数的区别,其实他们没有什么技术上的差别,真正的区别存在于设计和目的上,方法是用来对this对象进行操作的,而函数通常是独立的,并不需要使用this对象。
8.原型对象和继承
js对象都“继承”原型对象的属性,每个对象都有原型对象,原型对象的所有属性是以它为原型的对象的属性,也就是说,每个对象都继承原型对象的所有属性,
一个对象的原型是有创建并初始化该对象的构造函数定义的,js中的所有函数都有prototype属性,它引用一个对象,虽然原型对象初始化时是空的,但是你在其中定义的任何属性都会被构造函数创建
的所有对象继承。
构造函数定义了对象的类,并初始化了类中状态变量的属性,因为原型对象和构造函数关联在一起,所以类的每个成员都从原型对象继承了相同的属性,这说明原型对象是存放方法和其他常量属性的理
想场所。
继承是在查询一个属性值时自动发生的,属性并非从原型对象赋值到新的对象的,他们只不过看起来像是那些对象的属性,有两点重要的含义,一是:使用原型对象可以大量减少每个对象对内存的需求
量,因为对象可以继承许多属性;而且即使属性在对象被创建之后才添加属性到它的原型对象中,对象也能够继承这些属性。
属性的继承只发生在读属性值时,而在写属性值时不会发生。
因为原型对象的属性被一个类的所有对象共享,所以通常只用他们来定义类中所有对象的相同的属性,这使得原型对象适合于方法定义,另外原型对象还适合于具有常量的属性的定义,
a.原型和内部类
不只是用户定义的类有原型对象,像内部类同样具有原型对象,也可以给他们赋值,
e.g String.prototype.endsWith = function(o){
return (e == this,charAt(this.length-1));
}
9.面向对象的js
在面向对象的程序设计中,共有的概念是强类型和支持以类为基础的继承机制,根据这个评判标准,就可以证明js不是面向对象语言。
js对象可以具有大量的属性,而且还可以动态的将这些属性添加到对象中,这是对面对象c++和java做不到的,
虽然js没有类的概念,但是它用构造函数和原型对象模拟了类。
js和以类为基础的面向对象语言中,同一个类可以具有多个对象,对象是它所属的那个类的实力,所以任何类都可以有多个实例,js中的命名延勇了java中的命名约定,即命名类时以大写字母开头,命名对象时以小写字母开头,类帮助我们区分代码中的类和对象。
实例属性
每个对象都有它自己单据的实力属性的副本,为了模拟面向对象的程序设计语言,js中的实例属性是那些在对象中用构造函数创建的或初始化的属性。
实例方法
实例方法和实例数据非常的相似,实例方法是由特定对象或实例调用的,实例方法使用了关键字this来引用他们要操作的对象或实例,但是和实例属性不同额一点是每个实例方法都是由类的所有实例共享的,在js中,给类定义一个实例方法,是通过把构造函数的原型对象中的一个属性设置为函数值类实现的,这样,由那个构造函数创建的所有对象都会共享一个以继承的对函数的引用,而且使用上面素数的方法调用语法就能够调用这个函数。
类属性
类属性是一个与类相关联的变量,而不是和类的每个实例相关联的变量,每个类属性只有一个副本,它是通过类存取的,可以简单的定义了构造函数自身的一个属性来定义类属性
类方法
类方法是一个与类关联在一起的方法,而不是和类的实例关联在一起的方法,要调用类方法,就必须使用类本身,而不是使用类的特定实例。由于类方法不能通过一个特定对象调用,所以使用关键字this对它来说没有意义,和类属性一样,类方法是全局性的,
超类和子类
面向对象语言中有类层次的概念,每个类都有一个超类,他们从超类中继承属性和方法,类还可以被扩展,或者说子类化,这样其他子类就能继承它的行为,js中继承是以原型为基础的,而不是以类基础的继承机制,但是我们仍旧能够总结出累世的类层次图,在js中,类Object是最通用的类,其他所有类都是专用化了的版本,或者说的是Object的子类,另一种解释方法是Object是所有内部类的超类,所有类都继承了Object的基本方法。
举例说明:
类Complex的对象就继承了Complex.prototype对象的属性,而后者又继承了Object.prototype的属性,由此可以推出,对象Complex继承了两个对象的属性,在Complex对象中查询某个属性时,首先查询的是这个对象本身,如果在这个对喜爱那个中没有发现要查询的属性,就查询Complex.prototype对象,最后,如果在那个对象中还没有最后按到要查询的属性,就查询Object.prototype对象,注意类层次关系中的属性隐藏。参考P153
10.作为关联数组的对象
运算符“.”类存取一个对象属性,而数组更常用的存取书香运算赋是[],下面的两行代码是等价的:
obj.property ====== obj["property"],他们的语法区别是,前者的属性名是标识符,后者的属性名却是一个字符串,
在c、c++、java和其他类似的强类型语言中,一个对象的属性数是固定,而且必须预定义这些属性的名字,由于js是一种弱类型语言,它并没有采用这一规则,所以在用js编写的程序,可以为对象创建任意数目的属性,但是当你采用“.”运算符来存取一个对象的属性时,属性名时是用标识符表示的,而js程序性中,标识符必须被逐字的输入,他们不是一种数据类型,因此程序不能对他们进行操作。
constructor属性
每个对象都有constructor属性,它引用的是用来初始化该对象的构造函数。但是并不是所有的对象都具有自己唯一的constructor属性,相反,如果这个属性是从原型对象继承来的。
js会为我们定义的每一个构造函数都创建一个原型对象,并且将那个对象赋给构造函数的prototype属性。但是之前没有说明原型对象初始时是非空的,在原型对象创建之初,它包括一个constructor属性, 用来引用构造函数,也就是说,如果有一个函数f,那么属性f.prototype.constructor就总是等于f的。
由于构造函数定义了一个对象的类,所以属性construtor在确定给定对象的类型时是一个功能强大的工具。
并不能保证constructor属性总是存在的,例如,一个类的创建者可以用一个全新的对象来替换构造函数的原型对象,而新对象可能不具有有效的constructor属性。
toString()方法
toLocaleString()方法
valueOf()方法
js需要将一个对象转化成字符创之外的原型类型时,就调用它,这个函数返回的是能代表关键字this所引用的对象的值的数据。
hasOwnProperty()
如果兑现局部定义了一个非继承的属性,属性名是由一个字符串实际参数指定的,那么该方法就返回true,否则,它将返回false。
propertyIsEnumerable()
如果对象定义了一个属性,属性名是由一个字符串实际参数指定的,而且该属性可以用for/in循环枚举出来,那么该方法返回true,否则返回false。
注意:该方法只考虑对象直接定义的属性,而不考虑继承的属性,因为返回false可能是因为那个属性是不可枚举的,也可能是因为它虽然是可以枚举的,但却是个继承的属性。
怎么判断一个属性是可枚举的?
isPrototypeOf()
如果调用对象是实际参数指定的对象的原型对象,该方法返回true,否则返回false,该方法的用途和对象的constructoe属性相似。
1.函数
注意:定义函数时可以使用个数可变的参数,而且函数既可以有return语句,也可以没有return语句;如果函数不包含return语句,它就只执行函数体中的每条语句,然后返回给调用者undefined。
使用运算符typeof来检测参数的数据类型,使用if(!param)return;来判断是否存在该参数,因为js是一种无类型语言,所以你不能给函数的参数制定一个数据类型,而且js也不会检测传递的数据是不是那个函数所需要的类型,如果参数很重要时,就使用前面介绍的运算符进行检测。
不可变参数js的处理:如果传递的参数比函数需要的个数多,那么多余的几个参数被忽略掉,如果传递的参数比函数需要的个数少,那么多余的几个参数就会被赋予undefined,在大多数情况下,这回使得函数产生错误。
2.嵌套函数
a,函数定义中可以嵌套其他函数的定义,但是只能在在顶层全局代码和顶层函数代码中,不能出现在循环或条件语句中,并且这些限制只应用于由function语句声明的函数,函数直接量可以出现在任何js表达式中。
3.Function()构造函数
可以使用Function()构造函数和new运算符动态地定义函数, var f = new Function("x","y","return x*y;");它等价于:function f(x,y){return x*y;}
Function构造函数可以接受任意多个字符串参数,它的最后一个参数是函数的主体,其中可以包含任何js语句,语句之间用分号分隔。由于传递给构造函数Function()的参数中没有一个用于说明它要创建的函数名,用Function()构造函数创建的未命名函数有时被称作为“匿名函数”。
Function()函数存在的意义:因为Function()构造函数允许我们动态地建立和编译一个函数,它不会将我们限制在function语句预编译的函数体中;另一个原因是它能将函数定义为js表达式的一部分,而不是将其定义为一个语句;缺点是:这样做每次调用一个函数时,Function()构造函数都要对它进行编译,
4.函数直接量
函数直接量是一个表达式,它可以定义匿名函数。
function f(x){return x*x;} //function语句
var f = new Function("x","return x*x;"); //Function()构造函数
var f = function(X){return x*x;}; //函数直接量
虽然函数直接量创建的是未命名函数,但是它的语法也规定它可以指定函数名,这在编写调用自身的递归函数时特别的有用,e.g
var f= function fact(x){if(x<=1)return 1; else return x*fact(x-1);}
总结:function()函数可以任意的使用,具有通用性,Function()函数和函数直接量具有很多的相似性,他们都是未命名函数(函数直接量可以有函数名,尤其是在子调用函数中),函数直接量有个重要的有点,函数直接量只被解析和编译一次,而作为字符串传递给Function()构造函数的js代码则在每次调用构造函数时只需要被解析和编译一次。
函数最重要的特性就是他们能够被定义和调用,但是在js中函数并不只是一种语法,还可以是数据,可以把函数赋给变量、存储在对象的属性中或存储在数组的元素中,传递给函数。其实函数名并没有什么实际意义,它只是保存函数的变量的名字,可以将这个函数赋给其他的变量,它仍然以相同的方式起作用,
e.g function square(x){x*x;}
var a = square(4);
var b = square;//这种情况下b引用的函数和square的作用相同
var c = b(5);
除了赋给全局变量之外,还可以将函数赋给对象的属性,这是称函数为方法;也可以赋给数组元素。
e.g
var a = new Object; var a = new Object();
a.square = new Function("x","return x*x";);
y = o.square(16);
e.g
var a = new Array(3);
a[0] = function(x){return x*x;};
a[1] = 20;
a[2] = a[0](a[1]);
除这些之外,如何将函数作为参数传递给其他函数,
e.g
function add(x,y){return x+y;}
function subtract(x,y){return x-y;}
function multiply(x,y){return x*y;}
function dibide(x,y){return x/y;}
function operate(operator,operand1,operand2){
return operator(operand1,operand2);
}
var i = operate(add,operate(add,2,3),operate(multiply,4,5));
var operators = new Object();
operators["add"] = function(x,y){return x+y;}
operators["multiply"] = function(x,y){return x*y;}
operators["divide"] = function(x,y){return x/y;}
operators["pow"] = Math.pow;
function operate2(op_name,operand1,operand2){
if(operators[op_name] == null)return "unknow operator";
else return operators[op_name](operand1,operand2);
}
var j = operate2('add',"hello",operate2("add","","world"));
var k = operate2('pow',10,2);
5.函数的作用域,调用对象
函数的作用域中除了全局变量、函数内部的局部变量和形式参数外,函数还定义了一个特殊属性,
arguments,这个属性应用了另外一个特殊的对象-----Arguments对象,因为arguments属性是调用对象的一个属性,所以它的状态和局部变量以及函数的形式参数是相同的。
所以arguments标识符被看做是保留字,不能将它作为变量名或形式参数名。
6.Arguments对象
arguments它具有特殊的意义,是调用对象的一个特殊属性,用来引用Arguments对象,Arguments对象就像数组,可以按照数字获取传递给函数的参数值,但是它并非真正的Array对象。
arguments具有length属性,
可以使用arguments来检测调用函数使用了正确数目的实际参数,
注意:arguments并非真正的数组,它是一个Arguments对象,Arguments对象有一个非同寻常的特征,当函数具有命名了的参数时,Arguments对象的数组元素是存放函数参数的局部变量的同义词。
e.g
function(x){
alert(x); //显示参数的初始值
arguments[0] = null;//改变数组预算也会改变x
alert(x); //现在显示为“null”
除了数组元素,Arguments对象还定义了callee属性,用来引用当前正在执行的函数,这对未命名的函数调用自身非常有用。
e.g
function(x){
if(x<-1)return 1;
return x*arguments.callee(x-1);
}
7.函数的属性和方法
由于函数是对象,所以它具有数据和方法。
函数的length属性
函数的属性length和arguments属性的length不同,arguments数组的length属性指定了传递给该函数的实际参数数目,并且arguments属性的length只在函数内部起作用,而函数自身的length属性它是只读的,返回的是函数需要的实际参数的数目,并且函数的属性length函数体的内部和外部都在是有效的。
函数的prototype属性
每个函数都有一个prototype属性,它引用的是预定义的原型对象,原型对象在使用new运算符把函数作为构造函数时起作用。
函数自定义属性
有时候定义全局变量比较乱,可以通过自定义函数属性来解决
函数的apply()和call()方法
他们的第一个参数都是要调用的函数的对象,在函数体内这一参数是关键字this的值,call()的剩余参数是传递给要调用的函数的值,apply()的剩余参数是由数组指定的参数。
写出漂亮代码的七种方法
首先我想说明我本文阐述的是纯粹从美学的角度来写出代码,而非技术、逻辑等。以下为写出漂亮代码的七种方法:
1, 尽快结束 if语句
例如下面这个JavaScript语句,看起来就很恐怖:
- 1 function findShape(flags, point, attribute, list) {
-
- 2 if(!findShapePoints(flags, point, attribute)) {
-
- 3 if(!doFindShapePoints(flags, point, attribute)) {
-
- 4 if(!findInShape(flags, point, attribute)) {
-
- 5 if(!findFromGuide(flags,point) {
-
- 6 if(list.count() > 0 && flags == 1) {
-
- 7 doSomething();
-
- 8 }
-
- 9 }
-
- 10 }
-
- 11 }
-
- 12 }
-
- 13 }
1 function findShape(flags, point, attribute, list) {
2 if(!findShapePoints(flags, point, attribute)) {
3 if(!doFindShapePoints(flags, point, attribute)) {
4 if(!findInShape(flags, point, attribute)) {
5 if(!findFromGuide(flags,point) {
6 if(list.count() > 0 && flags == 1) {
7 doSomething();
8 }
9 }
10 }
11 }
12 }
13 }
但如果这么写就好看得多:
- 1 function findShape(flags, point, attribute, list) {
-
- 2 if(findShapePoints(flags, point, attribute)) {
-
- 3 return;
-
- 4 }
-
- 5
-
- 6 if(doFindShapePoints(flags, point, attribute)) {
-
- 7 return;
-
- 8 }
-
- 9
-
- 10 if(findInShape(flags, point, attribute)) {
-
- 11 return;
-
- 12 }
-
- 13
-
- 14 if(findFromGuide(flags,point) {
-
- 15 return;
-
- 16 }
-
- 17
-
- 18 if (!(list.count() > 0 && flags == 1)) {
-
- 19 return;
-
- 20 }
-
- 21
-
- 22 doSomething();
-
- 23
-
- 24 }
1 function findShape(flags, point, attribute, list) {
2 if(findShapePoints(flags, point, attribute)) {
3 return;
4 }
5
6 if(doFindShapePoints(flags, point, attribute)) {
7 return;
8 }
9
10 if(findInShape(flags, point, attribute)) {
11 return;
12 }
13
14 if(findFromGuide(flags,point) {
15 return;
16 }
17
18 if (!(list.count() > 0 && flags == 1)) {
19 return;
20 }
21
22 doSomething();
23
24 }
你可能会很不喜欢第二种的表述方式,但反映出了迅速返回if值的思想,也可以理解为:避免不必要的else陈述。
2, 如果只是简单的布尔运算(逻辑运算),不要使用if语句
例如:
- 1 function isStringEmpty(str){
-
- 2 if(str === "") {
-
- 3 return true;
-
- 4 }
-
- 5 else {
-
- 6 return false;
-
- 7 }
-
- 8 }
1 function isStringEmpty(str){
2 if(str === "") {
3 return true;
4 }
5 else {
6 return false;
7 }
8 }
可以写为:
- 1 function isStringEmpty(str){
-
- 2 return (str === "");
-
- 3 }
1 function isStringEmpty(str){
2 return (str === "");
3 }
3, 使用空白,这是免费的
例如:
1
- function getSomeAngle() {
-
- 2
-
- 3 radAngle1 = Math.atan(slope(center, point1));
-
- 4 radAngle2 = Math.atan(slope(center, point2));
-
- 5 firstAngle = getStartAngle(radAngle1, point1, center);
-
- 6 secondAngle = getStartAngle(radAngle2, point2, center);
-
- 7 radAngle1 = degreesToRadians(firstAngle);
-
- 8 radAngle2 = degreesToRadians(secondAngle);
-
- 9 baseRadius = distance(point, center);
-
- 10 radius = baseRadius + (lines * y);
-
- 11 p1["x"] = roundValue(radius * Math.cos(radAngle1) + center["x"]);
-
- 12 p1["y"] = roundValue(radius * Math.sin(radAngle1) + center["y"]);
-
- 13 pt2["x"] = roundValue(radius * Math.cos(radAngle2) + center["y"]);
-
- 14 pt2["y"] = roundValue(radius * Math.sin(radAngle2) + center["y");
-
- 15
-
- 16 }
function getSomeAngle() {
2 // Some code here then
3 radAngle1 = Math.atan(slope(center, point1));
4 radAngle2 = Math.atan(slope(center, point2));
5 firstAngle = getStartAngle(radAngle1, point1, center);
6 secondAngle = getStartAngle(radAngle2, point2, center);
7 radAngle1 = degreesToRadians(firstAngle);
8 radAngle2 = degreesToRadians(secondAngle);
9 baseRadius = distance(point, center);
10 radius = baseRadius + (lines * y);
11 p1["x"] = roundValue(radius * Math.cos(radAngle1) + center["x"]);
12 p1["y"] = roundValue(radius * Math.sin(radAngle1) + center["y"]);
13 pt2["x"] = roundValue(radius * Math.cos(radAngle2) + center["y"]);
14 pt2["y"] = roundValue(radius * Math.sin(radAngle2) + center["y");
15 // Now some more code
16 }
很多开发者不愿意使用空白,就好像这要收费一样。我在此并非刻意地添加空白,粗鲁地打断代码的连贯性。在实际编写代码的过程中,会很容易地发现在什么地方加入空白,这不但美观而且让读者易懂,如下:
- 1 function getSomeAngle() {
-
- 2
-
- 3 radAngle1 = Math.atan(slope(center, point1));
-
- 4 radAngle2 = Math.atan(slope(center, point2));
-
- 5
-
- 6 firstAngle = getStartAngle(radAngle1, point1, center);
-
- 7 secondAngle = getStartAngle(radAngle2, point2, center);
-
- 8
-
- 9 radAngle1 = degreesToRadians(firstAngle);
-
- 10 radAngle2 = degreesToRadians(secondAngle);
-
- 11
-
- 12 baseRadius = distance(point, center);
-
- 13 radius = baseRadius + (lines * y);
-
- 14
-
- 15 p1["x"] = roundValue(radius * Math.cos(radAngle1) + center["x"]);
-
- 16 p1["y"] = roundValue(radius * Math.sin(radAngle1) + center["y"]);
-
- 17
-
- 18 pt2["x"] = roundValue(radius * Math.cos(radAngle2) + center["y"]);
-
- 19 pt2["y"] = roundValue(radius * Math.sin(radAngle2) + center["y");
-
- 20
-
- 21 }
-
-
-
- 4, 不要使用无谓的注释
-
- 无谓的注释让人费神,这实在很讨厌。不要标出很明显的注释。在以下的例子中,每个人都知道代码表达的是“students id”,因而没必要标出。
-
- 1 function existsStudent(id, list) {
-
- 2 for(i = 0; i < list.length; i++) {
-
- 3 student = list[i];
-
- 4
-
- 5
-
- 6 thisId = student.getId();
-
- 7
-
- 8 if(thisId === id) {
-
- 9 return true;
-
- 10 }
-
- 11 }
-
- 12 return false;
-
- 13 }
1 function getSomeAngle() {
2 // Some code here then
3 radAngle1 = Math.atan(slope(center, point1));
4 radAngle2 = Math.atan(slope(center, point2));
5
6 firstAngle = getStartAngle(radAngle1, point1, center);
7 secondAngle = getStartAngle(radAngle2, point2, center);
8
9 radAngle1 = degreesToRadians(firstAngle);
10 radAngle2 = degreesToRadians(secondAngle);
11
12 baseRadius = distance(point, center);
13 radius = baseRadius + (lines * y);
14
15 p1["x"] = roundValue(radius * Math.cos(radAngle1) + center["x"]);
16 p1["y"] = roundValue(radius * Math.sin(radAngle1) + center["y"]);
17
18 pt2["x"] = roundValue(radius * Math.cos(radAngle2) + center["y"]);
19 pt2["y"] = roundValue(radius * Math.sin(radAngle2) + center["y");
20 // Now some more code
21 }
4, 不要使用无谓的注释
无谓的注释让人费神,这实在很讨厌。不要标出很明显的注释。在以下的例子中,每个人都知道代码表达的是“students id”,因而没必要标出。
1 function existsStudent(id, list) {
2 for(i = 0; i < list.length; i++) {
3 student = list[i];
4
5 // Get the student's id
6 thisId = student.getId();
7
8 if(thisId === id) {
9 return true;
10 }
11 }
12 return false;
13 }
5, 不要在源文件中留下已经删除的代码,哪怕你标注了
如果你使用了版本控制,那么你就可以轻松地找回前一个版本的代码。如果别人大费周折地读了你的代码,却发现是要删除的代码,这实在太恨人了。
//function thisReallyHandyFunction() {
// someMagic();
// someMoreMagic();
// magicNumber = evenMoreMagic();
// return magicNumber;
//}
6,不要有太长的代码
看太长的代码实在太费劲,尤其是代码本身的功能又很小。如下:
- 1 public static EnumMap<Category, IntPair> getGroupCategoryDistribution(EnumMap<Category, Integer> sizes, int groups) {
-
- 2 EnumMap<Category, IntPair> categoryGroupCounts = new EnumMap<Category,IntPair>(Category.class);
-
- 3
-
- 4 for(Category cat : Category.values()) {
-
- 5 categoryGroupCounts.put(cat, getCategoryDistribution(sizes.get(cat), groups));
-
- 6 }
1 public static EnumMap<Category, IntPair> getGroupCategoryDistribution(EnumMap<Category, Integer> sizes, int groups) {
2 EnumMap<Category, IntPair> categoryGroupCounts = new EnumMap<Category,IntPair>(Category.class);
3
4 for(Category cat : Category.values()) {
5 categoryGroupCounts.put(cat, getCategoryDistribution(sizes.get(cat), groups));
6 }
#
我并不是说非要坚持70个字符以内,但是一个比较理想的长度是控制在120个字符内。如果你把代码发布在互联网上,用户读起来就很困难。
7,不要在一个功能(或者函数内)有太多代码行
我的一个老同事曾经说Visual C++很臭,因为它不允许你在一个函数内拥有超过10,000行代码。我记不清代码行数的上限,不知道他说的是否正确,但我很不赞成他的观点。如果一个函数超过了50行,看起来有多费劲你知道么,还有没完没了的if循环,而且你还的滚动鼠标前后对照这段代码。对我而言,超过35行的代码理解起来就很困难了。我的建议是超过这个数字就把一个函数代码分割成两个。
本篇文章为在工作中使用JAVA反射的经验总结,也可以说是一些小技巧,以后学会新的小技巧,会不断更新。
在开始之前,我先定义一个测试类Student,代码如下:
- package chb.test.reflect;
-
- public class Student {
- private int age;
- private String name;
- public int getAge() {
- return age;
- }
- public void setAge(int age) {
- this.age = age;
- }
- public String getName() {
- return name;
- }
- public void setName(String name) {
- this.name = name;
- }
-
- public static void hi(int age,String name){
- System.out.println("大家好,我叫"+name+",今年"+age+"岁");
- }
- }<PRE></PRE>
package chb.test.reflect;
public class Student {
private int age;
private String name;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public static void hi(int age,String name){
System.out.println("大家好,我叫"+name+",今年"+age+"岁");
}
}
一、JAVA反射的常规使用步骤
反射调用一般分为3个步骤:
-
得到要调用类的class
-
得到要调用的类中的方法(Method)
-
方法调用(invoke)
代码示例:
- Class cls = Class.forName("chb.test.reflect.Student");
- Method m = cls.getDeclaredMethod("hi",new Class[]{int.class,String.class});
- m.invoke(cls.newInstance(),20,"chb");<PRE></PRE>
Class cls = Class.forName("chb.test.reflect.Student");
Method m = cls.getDeclaredMethod("hi",new Class[]{int.class,String.class});
m.invoke(cls.newInstance(),20,"chb");
二、方法调用中的参数类型
在方法调用中,参数类型必须正确,这里需要注意的是不能使用包装类替换基本类型,比如不能使用Integer.class代替int.class。
如我要调用Student的setAge方法,下面的调用是正确的:
- Class cls = Class.forName("chb.test.reflect.Student");
- Method setMethod = cls.getDeclaredMethod("setAge",int.class);
- setMethod.invoke(cls.newInstance(), 15);<PRE></PRE>
Class cls = Class.forName("chb.test.reflect.Student");
Method setMethod = cls.getDeclaredMethod("setAge",int.class);
setMethod.invoke(cls.newInstance(), 15);
而如果我们用Integer.class替代int.class就会出错,如:
- Class cls = Class.forName("chb.test.reflect.Student");
- Method setMethod = cls.getDeclaredMethod("setAge",Integer.class);
- setMethod.invoke(cls.newInstance(), 15);<PRE></PRE>
Class cls = Class.forName("chb.test.reflect.Student");
Method setMethod = cls.getDeclaredMethod("setAge",Integer.class);
setMethod.invoke(cls.newInstance(), 15);
jvm会报出如下异常:
- java.lang.NoSuchMethodException: chb.test.reflect.Student.setAge(java.lang.Integer)
- at java.lang.Class.getDeclaredMethod(Unknown Source)
- at chb.test.reflect.TestClass.testReflect(TestClass.java:23)<PRE></PRE>
java.lang.NoSuchMethodException: chb.test.reflect.Student.setAge(java.lang.Integer)
at java.lang.Class.getDeclaredMethod(Unknown Source)
at chb.test.reflect.TestClass.testReflect(TestClass.java:23)
三、static方法的反射调用
static方法调用时,不必得到对象示例,如下:
- Class cls = Class.forName("chb.test.reflect.Student");
- Method staticMethod = cls.getDeclaredMethod("hi",int.class,String.class);
- staticMethod.invoke(cls,20,"chb");
-
Class cls = Class.forName("chb.test.reflect.Student");
Method staticMethod = cls.getDeclaredMethod("hi",int.class,String.class);
staticMethod.invoke(cls,20,"chb");//这里不需要newInstance
//staticMethod.invoke(cls.newInstance(),20,"chb");
四、private的成员变量赋值
如果直接通过反射给类的private成员变量赋值,是不允许的,这时我们可以通过setAccessible方法解决。代码示例:
- Class cls = Class.forName("chb.test.reflect.Student");
- Object student = cls.newInstance();
- Field field = cls.getDeclaredField("age");
- field.set(student, 10);
- System.out.println(field.get(student));<PRE></PRE>
Class cls = Class.forName("chb.test.reflect.Student");
Object student = cls.newInstance();//得到一个实例
Field field = cls.getDeclaredField("age");
field.set(student, 10);
System.out.println(field.get(student));
运行如上代码,系统会报出如下异常:
- java.lang.IllegalAccessException: Class chb.test.reflect.TestClass can not access a member of class chb.test.reflect.Student with modifiers "private"
- at sun.reflect.Reflection.ensureMemberAccess(Unknown Source)
- at java.lang.reflect.Field.doSecurityCheck(Unknown Source)
- at java.lang.reflect.Field.getFieldAccessor(Unknown Source)
- at java.lang.reflect.Field.set(Unknown Source)
- at chb.test.reflect.TestClass.testReflect(TestClass.java:20)<PRE></PRE>
java.lang.IllegalAccessException: Class chb.test.reflect.TestClass can not access a member of class chb.test.reflect.Student with modifiers "private"
at sun.reflect.Reflection.ensureMemberAccess(Unknown Source)
at java.lang.reflect.Field.doSecurityCheck(Unknown Source)
at java.lang.reflect.Field.getFieldAccessor(Unknown Source)
at java.lang.reflect.Field.set(Unknown Source)
at chb.test.reflect.TestClass.testReflect(TestClass.java:20)
解决方法:
- Class cls = Class.forName("chb.test.reflect.Student");
- Object student = cls.newInstance();
- Field field = cls.getDeclaredField("age");
- field.setAccessible(true);
- field.set(student, 10);
- System.out.println(field.get(student));<PRE></PRE>
Class cls = Class.forName("chb.test.reflect.Student");
Object student = cls.newInstance();
Field field = cls.getDeclaredField("age");
field.setAccessible(true);//设置允许访问
field.set(student, 10);
System.out.println(field.get(student));
其实,在某些场合下(类中有get,set方法),可以先反射调用set方法,再反射调用get方法达到如上效果,代码示例:
- Class cls = Class.forName("chb.test.reflect.Student");
- Object student = cls.newInstance();
-
- Method setMethod = cls.getDeclaredMethod("setAge",Integer.class);
- setMethod.invoke(student, 15);
-
- Method getMethod = cls.getDeclaredMethod("getAge");
- System.out.println(getMethod.invoke(student));
|
Reflection 是 Java 程序开发语言的特征之一,它允许运行中的 Java 程序对自身进行检查,或者说“自审”,并能直接操作程序的内部属性。例如,使用它能获得 Java 类中各成员的名称并显示出来。JavaBean 是 reflection 的实际应用之一,它能让一些工具可视化的操作软件组件。这些工具通过 reflection 动态的载入并取得 Java 组件(类) 的属性。
1. 一个简单的例子
考虑下面这个简单的例子,让我们看看 reflection 是如何工作的。
import java.lang.reflect.*;
public class DumpMethods {
public static void main(String args[]) {
try {
Class c = Class.forName(args[0]);
Method m[] = c.getDeclaredMethods();
for (int i = 0; i < m.length; i++)
System.out.println(m[i].toString());
} catch (Throwable e) {
System.err.println(e);
}
}
}
按如下语句执行:
java DumpMethods java.util.Stack
它的结果输出为:
public java.lang.Object java.util.Stack.push(java.lang.Object)
public synchronized java.lang.Object java.util.Stack.pop()
public synchronized java.lang.Object java.util.Stack.peek()
public boolean java.util.Stack.empty()
public synchronized int java.util.Stack.search(java.lang.Object)
这样就列出了java.util.Stack 类的各方法名以及它们的限制符和返回类型。
这个程序使用 Class.forName 载入指定的类,然后调用 getDeclaredMethods 来获取这个类中定义了的方法列表。java.lang.reflect.Methods 是用来描述某个类中单个方法的一个类。还有就是getDeclaredMethod(para1,para2)来获取这个类中的具体某一个方法,其中para1是一个String类型,具体代表的是方法名,para2是个一个Class类型的数组,其中定义个方法的具体参数类型。
例如:
- Class cls = Class.forName("chb.test.reflect.Student");
- Method m = cls.getDeclaredMethod("方法名",new Class[]{int.class,String.class});
- m.invoke(cls.newInstance(),20,"chb");
总结:
//使用反射类调用某个类中的方法
Class c = Class.forName("com.inspur.reflect.MethodTest");
Method n = c.getDeclaredMethod("show", new Class[]{String.class,int.class});
n.invoke(c.newInstance(), "guoxzh",20);
a.使用Class.forName("类名")来获取类
b.其次使用getDeclaredMethods()方法获取该类所有的方法,也可以使用getDeclaredMethod("方法名",new Class[]{int.class,String.class})方法类获取具体的某一个方法
c.接着可以使用invoke(c.newInstance,param....)来调用具体的方法。
2.详细介绍开始使用 Reflection
用于 reflection 的类,如 Method,可以在 java.lang.relfect 包中找到。使用这些类的时候必须要遵循三个步骤:第一步是获得你想操作的类的 java.lang.Class 对象。在运行中的 Java 程序中,用 java.lang.Class 类来描述类和接口等。
下面就是获得一个 Class 对象的方法之一:
Class c = Class.forName("java.lang.String");
这条语句得到一个 String 类的类对象。还有另一种方法,如下面的语句:
Class c = int.class;
或者
Class c = Integer.TYPE;
它们可获得基本类型的类信息。其中后一种方法中访问的是基本类型的封装类 (如 Integer) 中预先定义好的 TYPE 字段。
第二步是调用诸如 getDeclaredMethods 的方法,以取得该类中定义的所有方法的列表。
一旦取得这个信息,就可以进行第三步了——使用 reflection API 来操作这些信息,如下面这段代码:
Class c = Class.forName("java.lang.String");
Method m[] = c.getDeclaredMethods();
System.out.println(m[0].toString());
它将以文本方式打印出 String 中定义的第一个方法的原型。
在下面的例子中,这三个步骤将为使用 reflection 处理特殊应用程序提供例证。
模拟 instanceof 操作符
得到类信息之后,通常下一个步骤就是解决关于 Class 对象的一些基本的问题。例如,Class.isInstance 方法可以用于模拟 instanceof 操作符:
class A {
}
public class instance1 {
public static void main(String args[]) {
try {
Class cls = Class.forName("A");
boolean b1 = cls.isInstance(new Integer(37)); //判断Integer(37)该对象是否是A类的对象
System.out.println(b1);
boolean b2 = cls.isInstance(new A());
System.out.println(b2);
} catch (Throwable e) {
System.err.println(e);
}
}
}
在这个例子中创建了一个 A 类的 Class 对象,然后检查一些对象是否是 A 的实例。Integer(37) 不是,但 new A() 是。
3.找出类的方法
找出一个类中定义了些什么方法,这是一个非常有价值也非常基础的 reflection 用法。下面的代码就实现了这一用法:
package com.inspur.reflect;
import java.lang.reflect.Method;
public class Methodtest1 {
private int abc(Object p,int x) throws NullPointerException{
if(p==null)throw new NullPointerException();
return x;
}
public static void main(String[] args) {
try{
Class cls = Class.forName("com.inspur.reflect.Methodtest1");
Method methodlist[]= cls.getDeclaredMethods();
for(int i = 0;i<methodlist.length;i++){
Method m = methodlist[i];
System.out.println("name=="+m.getName());//得到方法的名称
System.out.println("decl class=="+m.getDeclaringClass());//得到定义的类名
Class prev[] = m.getParameterTypes(); //取m方法中的所有参数
//遍历所有的参数
for(int j = 0; j<prev.length;j++){
System.out.println("param["+j+"]=="+prev[j]);
}
Class exec[] = m.getExceptionTypes(); //得到所有的异常
//遍历所有的异常
for(int k=0;k<exec.length;k++){
System.out.println("execption["+k+"]=="+exec[k]);
}
Class ret = m.getReturnType(); //得到每个方法的返回值
System.out.println("return leixing=="+ret.toString());
}
}catch(Throwable e){
System.err.println(e.getMessage());
}
}
}
这个程序首先取得 method1 类的描述,然后调用 getDeclaredMethods 来获取一系列的 Method 对象,它们分别描述了定义在类中的每一个方法,包括 public 方法、protected 方法、package 方法和 private 方法等。
如果你在程序中使用 getMethods 来代替 getDeclaredMethods,你还能获得继承来的各个方法的信息。同时你也可以使用Modifier.toString(m.getModifiers())来获取方法的限制属性。
取得了 Method 对象列表之后,要显示这些方法的参数类型、异常类型和返回值类型等就不难了。这些类型是基本类型还是类类型,都可以由描述类的对象按顺序给出。
输出的结果如下:
name==main
decl class==class com.inspur.reflect.Methodtest1
param[0]==class [Ljava.lang.String;
return leixing==void
name==abc
decl class==class com.inspur.reflect.Methodtest1
param[0]==class java.lang.Object
param[1]==int
execption[0]==class java.lang.NullPointerException
return leixing==int 4.获取构造器信息
获取类构造器的用法与上述获取方法的用法类似,如:
import java.lang.reflect.*;
public class constructor1 {
public constructor1() {
}
protected constructor1(int i, double d) {
}
public static void main(String args[]) {
try {
Class cls = Class.forName("constructor1");
Constructor ctorlist[] = cls.getDeclaredConstructors();
for (int i = 0; i < ctorlist.length; i++) {
Constructor ct = ctorlist[i];
System.out.println("name = " + ct.getName());
System.out.println("decl class = " + ct.getDeclaringClass());
Class pvec[] = ct.getParameterTypes();
for (int j = 0; j < pvec.length; j++)
System.out.println("param #" + j + " " + pvec[j]);
Class evec[] = ct.getExceptionTypes();
for (int j = 0; j < evec.length; j++)
System.out.println("exc #" + j + " " + evec[j]);
System.out.println("-----");
}
} catch (Throwable e) {
System.err.println(e);
}
}
}
这个例子中没能获得返回类型的相关信息,那是因为构造器没有返回类型。
这个程序运行的结果是:
name = constructor1
decl class = class constructor1
-----
name = constructor1
decl class = class constructor1
param #0 int
param #1 double
-----
5.获取类的字段(域)
找出一个类中定义了哪些数据字段也是可能的,下面的代码就在干这个事情:
import java.lang.reflect.*;
public class field1 {
private double d;
public static final int i = 37;
String s = "testing";
public static void main(String args[]) {
try {
Class cls = Class.forName("field1");
Field fieldlist[] = cls.getDeclaredFields();
for (int i = 0; i < fieldlist.length; i++) {
Field fld = fieldlist[i];
System.out.println("name = " + fld.getName());
System.out.println("decl class = " + fld.getDeclaringClass());
System.out.println("type = " + fld.getType());
int mod = fld.getModifiers();
System.out.println("modifiers = " + Modifier.toString(mod));
System.out.println("-----");
}
} catch (Throwable e) {
System.err.println(e);
}
}
}
这个例子和前面那个例子非常相似。例中使用了一个新东西 Modifier,它也是一个 reflection 类,用来描述字段成员的修饰语,如“private int”。这些修饰语自身由整数描述,而且使用 Modifier.toString 来返回以“官方”顺序排列的字符串描述 (如“static”在“final”之前)。这个程序的输出是:
name = d
decl class = class field1
type = double
modifiers = private
-----
name = i
decl class = class field1
type = int
modifiers = public static final
-----
name = s
decl class = class field1
type = class java.lang.String
modifiers =
-----
和获取方法的情况一下,获取字段的时候也可以只取得在当前类中申明了的字段信息 (getDeclaredFields),或者也可以取得父类中定义的字段 (getFields) 。
6.根据方法的名称来执行方法
文本到这里,所举的例子无一例外都与如何获取类的信息有关。我们也可以用 reflection 来做一些其它的事情,比如执行一个指定了名称的方法。下面的示例演示了这一操作:
import java.lang.reflect.*;
public class method2 {
public int add(int a, int b) {
return a + b;
}
public static void main(String args[]) {
try {
Class cls = Class.forName("method2");
Class partypes[] = new Class[2];
partypes[0] = Integer.TYPE;
partypes[1] = Integer.TYPE;
Method meth = cls.getMethod("add", partypes);
method2 methobj = new method2();
Object arglist[] = new Object[2];
arglist[0] = new Integer(37);
arglist[1] = new Integer(47);
Object retobj = meth.invoke(methobj, arglist);
Integer retval = (Integer) retobj;
System.out.println(retval.intValue());
} catch (Throwable e) {
System.err.println(e);
}
}
}
假如一个程序在执行的某处的时候才知道需要执行某个方法,这个方法的名称是在程序的运行过程中指定的 (例如,JavaBean 开发环境中就会做这样的事),那么上面的程序演示了如何做到。
上例中,getMethod 用于查找一个具有两个整型参数且名为 add 的方法。找到该方法并创建了相应的 Method 对象之后,在正确的对象实例中执行它。执行该方法的时候,需要提供一个参数列表,这在上例中是分别包装了整数 37 和 47 的两个 Integer 对象。执行方法的返回的同样是一个 Integer 对象,它封装了返回值 84。
7.创建新的对象
对于构造器,则不能像执行方法那样进行,因为执行一个构造器就意味着创建了一个新的对象 (准确的说,创建一个对象的过程包括分配内存和构造对象)。所以,与上例最相似的例子如下:
import java.lang.reflect.*;
public class constructor2 {
public constructor2() {
}
public constructor2(int a, int b) {
System.out.println("a = " + a + " b = " + b);
}
public static void main(String args[]) {
try {
Class cls = Class.forName("constructor2");
Class partypes[] = new Class[2];
partypes[0] = Integer.TYPE;
partypes[1] = Integer.TYPE;
Constructor ct = cls.getConstructor(partypes);
Object arglist[] = new Object[2];
arglist[0] = new Integer(37);
arglist[1] = new Integer(47);
Object retobj = ct.newInstance(arglist);
} catch (Throwable e) {
System.err.println(e);
}
}
}
根据指定的参数类型找到相应的构造函数并执行它,以创建一个新的对象实例。使用这种方法可以在程序运行时动态地创建对象,而不是在编译的时候创建对象,这一点非常有价值。
(这里如果使用无参构造器创建对象的话,这可以直接使用Class.forName("...").newInstance();来创建对象)
8.改变字段(域)的值
reflection 的还有一个用处就是改变对象数据字段的值。reflection 可以从正在运行的程序中根据名称找到对象的字段并改变它,下面的例子可以说明这一点:
import java.lang.reflect.*;
public class field2 {
public double d;
public static void main(String args[]) {
try {
Class cls = Class.forName("field2");
Field fld = cls.getField("d");
field2 f2obj = new field2();
System.out.println("d = " + f2obj.d);
fld.setDouble(f2obj, 12.34);
System.out.println("d = " + f2obj.d);
} catch (Throwable e) {
System.err.println(e);
}
}
}
这个例子中,字段 d 的值被变为了 12.34。
9.使用数组
本文介绍的 reflection 的最后一种用法是创建的操作数组。数组在 Java 语言中是一种特殊的类类型,一个数组的引用可以赋给 Object 引用。观察下面的例子看看数组是怎么工作的:
import java.lang.reflect.*;
public class array1 {
public static void main(String args[]) {
try {
Class cls = Class.forName("java.lang.String");
Object arr = Array.newInstance(cls, 10);
Array.set(arr, 5, "this is a test");
String s = (String) Array.get(arr, 5);
System.out.println(s);
} catch (Throwable e) {
System.err.println(e);
}
}
}
例中创建了 10 个单位长度的 String 数组,为第 5 个位置的字符串赋了值,最后将这个字符串从数组中取得并打印了出来。
下面这段代码提供了一个更复杂的例子:
import java.lang.reflect.*;
public class array2 {
public static void main(String args[]) {
int dims[] = new int[]{5, 10, 15};
Object arr = Array.newInstance(Integer.TYPE, dims);
Object arrobj = Array.get(arr, 3);
Class cls = arrobj.getClass().getComponentType();
System.out.println(cls);
arrobj = Array.get(arrobj, 5);
Array.setInt(arrobj, 10, 37);
int arrcast[][][] = (int[][][]) arr;
System.out.println(arrcast[3][5][10]);
}
}
例中创建了一个 5 x 10 x 15 的整型数组,并为处于 [3][5][10] 的元素赋了值为 37。注意,多维数组实际上就是数组的数组,例如,第一个 Array.get 之后,arrobj 是一个 10 x 15 的数组。进而取得其中的一个元素,即长度为 15 的数组,并使用 Array.setInt 为它的第 10 个元素赋值。
注意创建数组时的类型是动态的,在编译时并不知道其类型。
摘要: 转自其他博客《收藏》
(1) 选择最有效率的表名顺序(只在基于规则的优化器中有效):
ORACLE的解析器按照从右到左的顺序处理FROM子句中的表名,FROM子句中写在最后的表(基础表 driving table)将被最先处理,在FROM子句中包含多个表的情况下,你必须选择记录条数最少的表作为基础表。如果有3个以上的表连接查询,...
阅读全文
1,使用Spring 的 ActionSupport
2,使用Spring 的 DelegatingRequestProcessor 类。
3,全权委托。
无论用那种方法来整合第一步就是要为struts来装载spring的应用环境。 就是在 struts 中加入一个插件。
struts-config.xml中
<plug-in className="org.springframework.web.struts.ContextLoaderPlugIn">
<set-property property="contextConfigLocation" value="/WEB-INF/applicationContext.xml"/>
</plug-in>
|
spring 的配置文件被作为参数配置进来。这样可以省略对web.xml 文件中的配置。确保你的applicationContext.xml 在WEB-INF目录下面
1、使用Spring的ActionSupport .
Spring 的ActionSupport 继承至org.apache.struts.action.Action
ActionSupport的子类可以或得 WebApplicationContext类型的全局变量。通过getWebApplicationContext()可以获得这个变量。
这是一个 servlet 的代码:
public class LoginAction extends org.springframework.web.struts.ActionSupport {
public ActionForward execute(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response) {
LoginForm loginForm = (LoginForm) form;// TODO Auto-generated method stub
//获得 WebApplicationContext 对象
WebApplicationContext ctx = this.getWebApplicationContext();
LoginDao dao = (LoginDao) ctx.getBean("loginDao");
User u = new User();
u.setName(loginForm.getName());
u.setPwd(loginForm.getPwd());
if(dao.checkLogin(u)){
return mapping.findForward("success");
}else{
return mapping.findForward("error");
}
}
}
applicationContext.xml 中的配置
<beans>
<bean id="loginDao" class="com.cao.dao.LoginDao"/>
</beans>
|
这中配置方式同直接在web.xml文件配置差别不大。
注意:Action继承自 org.springframework.web.struts.ActionSupport 使得struts和spring耦合在一起。
但实现了表示层和业务逻辑层的解耦(LoginDao dao = (LoginDao) ctx.getBean("loginDao"))。
2、使用Spring 的 DelegatingRequestProcessor 类
DelegatingRequestProcessor 继承自 org.apache.struts.action.RequestProcessor 并覆盖了里面的方法。
sturts-config.xml 中
processorClass="org.springframework.web.struts.DelegatingRequestProcessor"/> 通过 来替代
org.apache.struts.action.RequestProcessor 的请求处理。
public class LoginAction extends Action {
//利用spring来注入这个对象。
private LoginDao dao ;
public void setDao(LoginDao dao) {
System.out.println("执行注入");
this.dao = dao;
}
public LoginDao getDao() {
return dao;
}
public ActionForward execute(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response) {
LoginForm loginForm = (LoginForm) form;// TODO Auto-generated method stub
//这样一改这行代码似乎没有必要了。
//WebApplicationContext ctx = this.getWebApplicationContext();
//LoginDao dao = (LoginDao) ctx.getBean("loginDao");
User u = new User();
u.setName(loginForm.getName());
u.setPwd(loginForm.getPwd());
//直接用dao来调用spring会将这个对象实例化。
if(dao.checkLogin(u)){
return mapping.findForward("success");
}else{
return mapping.findForward("error");
}
}
}
这里的。
LoginAction extends Action 说明 struts没有和spring 耦合。
看一下
applicationContext.xml 中的配置。
<beans>
<bean id="loginDao" class="com.cao.dao.LoginDao"/>
<bean name="/login" class="com.cao.struts.action.LoginAction">
<property name="dao">
<ref local="loginDao"/>
</property>
</bean>
</beans>
|
这里 name="/login" 与struts 中的path匹配
class="com.cao.struts.action.LoginAction" 与struts 中的type匹配
还要为 LoginAction 提供必要的setXXX方法。 获得ApplicationCotext和依赖注入的工作都在DelegatingRequestProcessor中完成。
3,全权委托:
Action 的创建和对象的依赖注入全部由IOC容器来完成。使用Spring的DelegatingAcionProxy来帮助实现代理的工作
org.springframework.web.struts.DelegatingActiongProxy继承于org.apache.struts.action.Action .
全权委托的配置方式同 方式 2 类似 (applcationContext.xml文件的配置和 Action类的实现方式相同)。
<struts-config>
<data-sources />
<form-beans >
<form-bean name="loginForm"
type="com.cao.struts.form.LoginForm" />
</form-beans>
<global-exceptions />
<global-forwards />
<action-mappings >
<!-- type指向的是spring 的代理类 -->
<action
attribute="loginForm"
input="login.jsp"
name="loginForm"
path="/login"
scope="request"
type="org.springframework.web.struts.DelegatingActionProxy" >
<forward name="success" path="/ok.jsp" />
<forward name="error" path="/error.jsp" />
</action>
</action-mappings>
<message-resources parameter="com.cao.struts.ApplicationResources" />
<plug-in className=
"org.springframework.web.struts.ContextLoaderPlugIn">
<set-property property="contextConfigLocation"
value="/WEB-INF/applicationContext.xml"/>
</plug-in>
</struts-config>
不同之处
1, <action>中 type指向的是spring 的代理类
2, 去掉struts-config.xml中 <controller >
|
三种整和方式中我们优先选用 全权委托的方式。
理由:
1,第一种使得过多的耦合了Spring和Action .
2,RequestProcessor类已经被代理 如果要再实现自己的实现方式(如:编码处理)怕有点麻烦。
总结一下:
整合工作中的步骤:
1,修改struts-config.xml
2, 配置applicationContext.xml
3, 为Action添加get/set方法 来获得依赖注入的功能。