#
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方法 來獲得依賴注入的功能。