久久99精品久久久久久琪琪,久久人人爽人人爽人人片亞洲,熟妇人妻无码中文字幕,亚洲精品无码久久久久久久

詞法分析設(shè)計(jì)實(shí)驗(yàn)報(bào)告(附代碼)[精選合集]

時(shí)間:2019-05-14 04:22:03下載本文作者:會(huì)員上傳
簡介:寫寫幫文庫小編為你整理了多篇相關(guān)的《詞法分析設(shè)計(jì)實(shí)驗(yàn)報(bào)告(附代碼)》,但愿對(duì)你工作學(xué)習(xí)有幫助,當(dāng)然你在寫寫幫文庫還可以找到更多《詞法分析設(shè)計(jì)實(shí)驗(yàn)報(bào)告(附代碼)》。

第一篇:詞法分析設(shè)計(jì)實(shí)驗(yàn)報(bào)告(附代碼)

實(shí)驗(yàn)一

詞法分析設(shè)計(jì)

實(shí)驗(yàn)學(xué)時(shí):4 實(shí)驗(yàn)類型:綜合 實(shí)驗(yàn)要求:必修

一、實(shí)驗(yàn)?zāi)康?/p>

通過本實(shí)驗(yàn)的編程實(shí)踐,使學(xué)生了解詞法分析的任務(wù),掌握詞法分析程序設(shè)計(jì)的原理和構(gòu)造方法,使學(xué)生對(duì)編譯的基本概念、原理和方法有完整的和清楚的理解,并能正確地、熟練地運(yùn)用。

二、實(shí)驗(yàn)內(nèi)容

用VC++/VB/JAVA語言實(shí)現(xiàn)對(duì)C語言子集的源程序進(jìn)行詞法分析。通過輸入源程序從左到右對(duì)字符串進(jìn)行掃描和分解,依次輸出各個(gè)單詞的內(nèi)部編碼及單詞符號(hào)自身值;若遇到錯(cuò)誤則顯示“Error”,然后跳過錯(cuò)誤部分繼續(xù)顯示 ;同時(shí)進(jìn)行標(biāo)識(shí)符登記符號(hào)表的管理。以下是實(shí)現(xiàn)詞法分析設(shè)計(jì)的主要工作:(1)從源程序文件中讀入字符。

(2)統(tǒng)計(jì)行數(shù)和列數(shù)用于錯(cuò)誤單詞的定位。(3)刪除空格類字符,包括回車、制表符空格。

(4)按拼寫單詞,并用(內(nèi)碼,屬性)二元式表示。(屬性值——token的機(jī)內(nèi)表示)(5)如果發(fā)現(xiàn)錯(cuò)誤則報(bào)告出錯(cuò)

(6)根據(jù)需要是否填寫標(biāo)識(shí)符表供以后各階段使用。單詞的基本分類: ? ? ? ? ? ? 關(guān)鍵字:由程序語言定義的具有固定意義的標(biāo)識(shí)符。也稱為保留字例如 標(biāo)識(shí)符:用以表示各種名字,如變量名、數(shù)組名、函數(shù)名; 常數(shù): 任何數(shù)值常數(shù)。如 125, 1,0.5,3.1416; 運(yùn)算符:+、-、*、/;

關(guān)系運(yùn)算符: <、<=、=、>、>=、<>; 分界符: ;、,、(、)、[、]; if、for、while、printf ;

單詞種別碼為1。

三、實(shí)驗(yàn)要求

1、編程時(shí)注意編程風(fēng)格:空行的使用、注釋的使用、縮進(jìn)的使用等。

2、將標(biāo)識(shí)符填寫的相應(yīng)符號(hào)表須提供給編譯程序的以后各階段使用。

3、根據(jù)測試數(shù)據(jù)進(jìn)行測試。測試實(shí)例應(yīng)包括以下三個(gè)部分: ? 全部合法的輸入。? 各種組合的非法輸入。? 由記號(hào)組成的句子。

4、詞法分析程序設(shè)計(jì)要求輸出形式: 例:輸入VC++語言的實(shí)例程序:

If i=0 then

n++;a﹤= 3b %);輸出形式為:

單詞

二元序列

類 型

(單詞種別,單詞屬性)

for

(1,for)

關(guān)鍵字

i

(6,i)

標(biāo)識(shí)符

=

(4,=)

關(guān)系運(yùn)算符0

(5,0)

常數(shù)

then

(1,then)

關(guān)鍵字 n

(6,n)

標(biāo)識(shí)符

++

Error

Error

(2,;)

分界符

位置(行,列)

(1,1)

(1,2)

(1,3)

(1,4)

(1,5)

(1,6)

(1,7)

(1,8)

a

(6,a)

標(biāo)識(shí)符

(2,1)﹤=

(4,<=)

關(guān)系運(yùn)算符

(2,2)3b

Error

Error

(2,4)%

Error

Error

(2,4))

(2,))

分界符

(2,5);

(2,;)

分界符

(2,6)

實(shí)驗(yàn)報(bào)告正文:

? 功能描述:該程序具有詞法分析功能,即面對(duì)一段程序源代碼,通過該程序,能檢查出源代碼是否由詞法錯(cuò)誤。

?

三、詞法分析實(shí)驗(yàn)設(shè)計(jì)思想及算法: ? 首先構(gòu)造六個(gè)表,key[]={“auto”,“break”,“case”,“catch”,“char”,“class”,“const”,“continue”,“default”,“delete”,“do”,“double”,“else”,“enum”,“float”,“for”,“if”,“int”,“l(fā)ong”,“new”,“private”,“protected”,“public”,“register”,“return”,“short”,“static”,“struct”,“switch”,“this”,“void”,“while”,“then”};關(guān)鍵字表, 單詞種別碼1;

Delimiter[]={“;”,“(”,“)”,“[”,“]”,“,”,“.”,“{”,“}”};分界符表 單詞種別碼2 Operator[]={“+”,“-”,“*”,“/”};算術(shù)運(yùn)算符表

單詞種別碼3 R_operators[]={“<”,“<=”,“==”,“>”,“>=”},關(guān)鍵字表 , 單詞種別碼1;string Number[100];常數(shù)表

單詞種別碼5;string Identifier[100];標(biāo)示符表

單詞種別碼6;構(gòu)造關(guān)鍵字判斷函數(shù)Iskey(),字母判斷函數(shù)Isletter(),數(shù)字判斷函數(shù)Isnumber();構(gòu)造標(biāo)示符判別函數(shù)InsertId(),若輸入的標(biāo)示符在標(biāo)示符數(shù)組Identifier []中,返回其下標(biāo),若不在,將該標(biāo)示符插到數(shù)組末尾。構(gòu)造標(biāo)示符判別函數(shù)InsertNumber(),若輸入的數(shù)字在數(shù)字?jǐn)?shù)組Number[]中,返回其下標(biāo),若不在,將該數(shù)字插到數(shù)組末尾。具體分析函數(shù)analyse()具體實(shí)現(xiàn)輸入源代碼的識(shí)別。anaiyse()構(gòu)造思路,程序設(shè)計(jì)圖:

綜合以上分析,畫出整個(gè)程序的運(yùn)行分析程序圖,如下: 開始 輸入源文件路徑否 路徑是否有效是打開源文件初始化文件指針識(shí)別指針內(nèi)容文件結(jié)束?否是空格,空白或換行嗎是跳過該字符是結(jié)束否是字母嗎是將字符加入字符數(shù)組Word[]否是數(shù)字嗎否是界符嗎否將字符加入字符數(shù)組Word[]是將字符加入字符數(shù)組Word[]是指向下一字符識(shí)別指針內(nèi)容是輸出word為界符輸出Word內(nèi)容為不可識(shí)別將字符加入字符數(shù)組Word[]將字符加入字符數(shù)組Word[]指向下一字符指向下一字符是字母惑數(shù)字嗎回退否將word與關(guān)鍵字表key進(jìn)行匹配輸出word為普通標(biāo)示符是數(shù)字嗎否輸出word為常數(shù)指向下一字符否匹配?是輸出word為關(guān)鍵字整個(gè)程序的運(yùn)行分析程序圖

? 軟件的測試方法和測試結(jié)果:

首先,將要分析的源代碼寫入一個(gè)文本,存于磁盤中,然后運(yùn)行程序,輸入源代碼文件存放的路徑,若輸入路徑正確,程序?qū)⒆詣?dòng)分析源代碼,若輸入路徑不正確,程序?qū)@示,路徑錯(cuò)誤,請(qǐng)重新輸入的提示。下面為具體的運(yùn)行實(shí)例: 源代碼為:If i=0 then

n++;a﹤= 3b %)

輸出滿足要求。

? 實(shí)驗(yàn)總結(jié)(設(shè)計(jì)的特點(diǎn)、不足、收獲與體會(huì)):

通過此次實(shí)驗(yàn),讓我了解到如何設(shè)計(jì)、編制并調(diào)試詞法分析程序,熟悉了構(gòu)造詞法分析程序的手工方式的相關(guān)原理,加深了對(duì)編譯原理詞法分析的理解,本次使用C++語言直接編寫此法分析程序,也讓我重新熟悉了C++語言的相關(guān)內(nèi)容,加深了對(duì)C++語言的用途的理解。本程序的數(shù)據(jù)輸入采取直接從文件中讀取,而不是由鍵盤輸入,因此在測試過程中,輸入得到大大簡化,但是本程序的關(guān)鍵字表只初始化了一部分關(guān)鍵字,還可繼續(xù)擴(kuò)充(只需擴(kuò)大數(shù)組,向其中補(bǔ)充要添加的關(guān)鍵字),而且程序的測試數(shù)據(jù)存在不足,程序可能存在未發(fā)現(xiàn)的漏洞,以上兩點(diǎn)有待改善。附錄該程序的源代碼: #include #include using namespace std;//數(shù)據(jù)定義 #define MAX 33 char ch =' ';static int line=1,row=0;int NumberCount=0,IdCount=0;string key[]={“auto”,“break”,“case”,“catch”,“char”,“class”,“const”,“continue”,“default”,“delete”,“do”,“double”, “else”,“enum”,“float”,“for”,“if”,“int”,“l(fā)ong”,“new”,“private”,“protected”,“public”,“register”,“return”,“short”,“static”, “struct”,“switch”,“this”,“void”,“while”,“then”};//關(guān)鍵字表 單詞種別碼1 string Delimiter[]={“;”,“(”,“)”,“[”,“]”,“,”,“.”,“{”,“}”};//分界符表 單詞種別碼2 string Operator[]={“+”,“-”,“*”,“/”};//算術(shù)運(yùn)算符表 單詞種別碼3 string R_operators[]={“<”,“<=”,“==”,“>”,“>=”};//關(guān)系運(yùn)算符表 單詞種別碼4 string Number[100];//常數(shù)表 單詞種別碼5 string Identifier[100];//標(biāo)示符表 單詞種 別碼6//數(shù)據(jù)分析 int Iskey(string c){ //關(guān)鍵字判斷 int i;for(i=0;i='a'))||((c<='Z')&&(c>='A'))){ if((ch<='Z')&&(ch>='A'))ch=ch+32;//轉(zhuǎn)換成小寫 return 1;} else return 0;} int IsNumber(char c){ //判斷是否為數(shù)字 if(c>='0'&&c<='9')return 1;else return 0;} //將arr中的標(biāo)示符插入符號(hào)表 并且返回符號(hào)表的指針 int InsertId(string s){ for(int i=0;i' :{ch=fgetc(fpin);if(ch=='=')cout<<”>=“<<”tt(4,>=)“<<”tt關(guān)系運(yùn)算符“<<”tt(“<“<<”tt(4,>)“<<”tt關(guān)系運(yùn)算符“<<”tt(“<')cout<<”<>“<<”tt(4,<>)“<<”tt關(guān)系運(yùn)算符“<<”t(“<>in_fn;if((fpin=fopen(in_fn,”r“))!=NULL)break;else cout<<”文件路徑錯(cuò)誤!請(qǐng)輸入源文件名(包括路徑和后綴名):“;} cout<<”n********************分析如下*********************“<

第二篇:《編譯原理》課程(詞法分析)實(shí)驗(yàn)報(bào)告

一.實(shí)驗(yàn)序號(hào):《編譯原理》第一次實(shí)驗(yàn)

二.實(shí)驗(yàn)題目:詞法分析

三.實(shí)驗(yàn)日期:2010.10

四.實(shí)驗(yàn)環(huán)境(操作系統(tǒng),開發(fā)語言)

操作系統(tǒng):Windows

開發(fā)語言:C

五.實(shí)驗(yàn)內(nèi)容(實(shí)驗(yàn)要求)

a)將標(biāo)識(shí)符的詞法改為“以大寫字母或小寫字母開頭,后面可以跟大寫字

母或小寫字母或數(shù)字或下劃線”。

b)將<條件>中的表示相等關(guān)系的單詞“=”改為“= =”

c)將原來的無小數(shù)的數(shù)改為可以有小數(shù)的數(shù)

六.實(shí)驗(yàn)步驟

a)打開VC++,找到getsym()項(xiàng)目。

int getsym()

{...}

在getsym()函數(shù)中設(shè)置斷點(diǎn),F(xiàn)10逐過程調(diào)試

根據(jù)要求a修改為

if(ch>='a'&&ch<='z'||ch>='A'&&ch<='Z')

往后面看,修改while(ch>='a' && ch<='z' || ch>='0' && ch<='9' ||ch>='A' && ch<='Z' || ch=='_');

b)在檢測賦值符號(hào)的程序段中找到等號(hào) = 的判斷代碼,改變成為 = = 即

可。

c)在獲取整數(shù)數(shù)字的值的程序段后面添加判斷小數(shù)點(diǎn)的代碼。如果是,即

讀取符號(hào)并且按照小數(shù)的要求將其縮小并且累加到總的符號(hào)串中。

七.實(shí)驗(yàn)體會(huì)(包括收獲、心得體會(huì)、存在的問題及解決問題的方法、建議等)

通過實(shí)驗(yàn),如果要修改代碼的話,首先應(yīng)該讀懂源碼,在修改之前了解到程序段的功能是什么,然后再在相應(yīng)的行進(jìn)行修改添加,再進(jìn)行合理的調(diào)試。如果問題太過困難可以查詢資料或與同學(xué)進(jìn)行討論

八.實(shí)驗(yàn)結(jié)果(關(guān)鍵源程序)

a)

int getsym()

{

int i,j,k;

while(ch==' '||ch==10||ch==9)/*忽略空格,換行和TAB*/{

getchdo;

}

if(ch>='a'&&ch<='z'||ch>='A'&&ch<='Z')/*名字或保留字以a..zA。Z開頭*/{

k=0;

do{

if(k

{

a[k]=ch;

k++;

}

getchdo;

}while(ch>='a' && ch<='z' || ch>='0' && ch<='9' || ch>='A' && ch<='Z' || ch=='_');//

if(ch>='0'&&ch<='9')/*檢測是否為數(shù)字,以0..9開頭*/{

k=0;

num=0;

sym=number;

do{

//435

num=10*num+ch-'0';

k++;

getchdo;

}while(ch>='0' && ch<='9');

if(ch=='.')

{

k++;

sym=period;

getchdo;

sym=number;

int div=10;

do{num=num+(ch-'0')/div;

k++;

getchdo;

div=div*10;

}while(ch>='0'&&ch<='9');

}

b)

else

{

if(ch=='>')//檢測大于或大于等于符號(hào){

getchdo;

if(ch=='=')//add by M

{

sym=geq;//構(gòu)成>=

getchdo;

}

else

{

sym=gtr;//否則就是一個(gè)單獨(dú)的>號(hào)}

}

else

{

if(ch=='=')

{

getchdo;

if(ch=='=')

{

sym=deq;

getchdo;

}

else

{

sym=eql;

}

}

c)else

{if(ch == ’.’)

{k=10;

getchdo;

do{num=num+(ch-'0')/k;

k=k*10;

getchdo;

}while(ch>='0'&&ch<='9');}

}

第三篇:詞法分析小結(jié)

詞法分析是編譯器工作的第一階段,它的工作就是從輸入(源代碼)中取得token,以作為parser(語法分析)的輸入,一般在詞法分析階段都會(huì)把一些無用的空白字符(white space,即空格、tab和換行)以及注釋剔除,以降低下一步分析的復(fù)雜度,詞法分析器一般會(huì)提供一個(gè)gettoken()這樣的方法,parser可以在做語法分析時(shí)調(diào)用詞法分析器的這個(gè)方法來得到下一個(gè)token,所以詞法分析器并不是一次性遍歷所有源代碼,而是采取這種on-demand的方式:只在parser需要時(shí)才工作,并且每次只取一個(gè)token。

token和lexeme

首先,token不等于lexeme。token和lexeme的關(guān)系就類似于面向?qū)ο笳Z言中“類”和“實(shí)例”(或“對(duì)象”)之間的關(guān)系,這個(gè)用中文不知該如何解釋才好,比如語言中的變量a和b,它們都屬于同一種token:identifier,而a的lexeme是”a”,b則是”b”,而每個(gè)關(guān)鍵字都是一種token。token可以附帶有一個(gè)值屬性,例如變量a,當(dāng)調(diào)用詞法分析器的gettoken()時(shí),會(huì)返回一個(gè)identifier類型的token,這個(gè)token帶有一個(gè)屬性“a”,屬性可以是多樣的,例如表示數(shù)字的token可以帶有一個(gè)表示數(shù)字值的屬性,它是整型的。

如下代碼:

int age = 23;

int count = 50;

可以依次提取出8個(gè)token:int(值為”int”),id(值為”age”),assign(值為”=”),number(值為整型數(shù)值23),int(值為”int”),id(值為”count”),assign(值為”=”),number(值為50)

正則表達(dá)式

正則表達(dá)式可以用來描述字符串模式,例如我們可以用digit+來表示number的token,其中digit表示單個(gè)數(shù)字(這里說正則表達(dá)式并不完全和實(shí)現(xiàn)的正則引擎所識(shí)別的正則表達(dá)式等價(jià),這里只是為了描述問題而已)。

然而像c語言的的多行注釋,用正則表達(dá)式來描述就比較麻煩,此時(shí)更傾向于直接用有窮自動(dòng)機(jī)(finite automaton)來描述,因?yàn)橛盟鼇砻枋龇浅V庇^且很容易。

有窮自動(dòng)機(jī)(finite automata)

有窮自動(dòng)機(jī)也稱為有限狀態(tài)機(jī),狀態(tài)在輸入字符的作用下發(fā)生遷移,因此,它可以用來識(shí)別token,也因此,我們只要畫得出fa,之后再用代碼實(shí)現(xiàn)這個(gè)fa,那詞法分析器也就差不多弄好了。

有窮自動(dòng)機(jī)分確定性(dfa)和非確定性(nfa)兩種,如果對(duì)于同一個(gè)輸入,只會(huì)有一個(gè)確定的狀態(tài)遷移路線,也就是只有一個(gè)確定的“下一狀態(tài)”,那就是dfa,否則就是nfa。

因?yàn)閐fa對(duì)于同一個(gè)輸入只有一個(gè)確定的下一狀態(tài),所以詞法分析器當(dāng)然優(yōu)先采用它,那nfa拿來干嘛用呢?nfa用來做描述用時(shí)更方便,我們可以非常迅速地畫出一個(gè)識(shí)別token的nfa圖,但要想直接畫出個(gè)dfa那要?jiǎng)硬簧倌X筋。

根據(jù)正則表達(dá)式構(gòu)建nfa

如上所述,nfa更容易畫出,那我們就先研究nfa,在定義token時(shí),我們可以用正則表達(dá)式來描述它,因?yàn)檎齽t表達(dá)式干這行很合適,例如一個(gè)digit+就可以描述數(shù)字,多方便。因此,我們需要根據(jù)正則表達(dá)式畫出與之等價(jià)的nfa。而這個(gè)算法非常簡單,就是tompson’s construction,這個(gè)書上寫得很清楚了。

將nfa轉(zhuǎn)化成dfa(nfa的確定化)

對(duì)于計(jì)算機(jī)來說,面對(duì)同一個(gè)輸入,如果有多個(gè)下一狀態(tài),那計(jì)算機(jī)就不清楚要轉(zhuǎn)到哪個(gè)狀態(tài),所以我們期望能從正則表達(dá)式得到dfa,而不是nfa,因?yàn)檫@樣將來編程實(shí)現(xiàn)時(shí)比較自然(同一輸入有確定的一個(gè)下一狀態(tài)),而幸運(yùn)的是,每個(gè)nfa都可以轉(zhuǎn)化成dfa。為什么nfa可以轉(zhuǎn)化成dfa?因?yàn)閒a(finite automata)中的狀態(tài)都是我們自己畫的,只要fa能正確的識(shí)別token,那就ok了,也就是,如果nfa和dfa都可以達(dá)到一樣的效果:識(shí)別token,那其它的我們就不管了。

實(shí)現(xiàn)詞法分析器

對(duì)于一個(gè)token,比如用來表示數(shù)字的token:num,我們可以用正則表達(dá)式描述它,然后畫出nfa,再將nfa轉(zhuǎn)化成dfa,再最小化dfa的狀態(tài),但是我們的詞法分析器是不是分析一個(gè)token,所以我們要把所有類型的token的dfa合并成一個(gè)dfa,這樣,這個(gè)dfa也就可以識(shí)別語言的所有token了,如果在某一連串的輸入下,dfa達(dá)不到終結(jié)狀態(tài),那就說明源代碼有錯(cuò)誤了。

我用c#實(shí)現(xiàn)了一個(gè)用于《compiler construction: principles and practice》中tiny語言的詞法分析器,tiny語言有關(guān)鍵字:if, then, else, end, repeat, until, read, write,有操作符+,-,*,/,=,<,(,),;,:=(全角逗號(hào)不算,是文章的分隔符)這10個(gè),然后其余的token有number(一或多個(gè)數(shù)字)和identifier(一或多個(gè)字母),其dfa如下圖:

上面這張圖和《編譯原理及實(shí)踐》中的一樣,其中的帶中括號(hào)的輸入說明這個(gè)輸入是lookahead的,在匹配成功后是要重新放回輸入流中的,比如識(shí)別num時(shí),如果發(fā)現(xiàn)個(gè)非digit的,那就說明識(shí)別到了一個(gè)number,但是最后識(shí)別的那個(gè)非digit字符是要放回輸入流的,因?yàn)樗糁乱淮巫R(shí)別。

其中從start到done的那個(gè)other,指所有非white space,非{,非letter,非digit,也非:的字符,它有可能是合法的+, *, /這些,也可能是不合法的其它輸入,如#號(hào)。因此,done這個(gè)狀態(tài)只是說本次gettoken已經(jīng)結(jié)束,狀態(tài)機(jī)是有可能因?yàn)椴缓戏ǖ妮斎攵M(jìn)入done狀態(tài)的。究竟從start到done是因?yàn)楹戏ǖ模?號(hào)導(dǎo)致的,還是由不合法的如#號(hào)導(dǎo)致的,將在代碼中實(shí)現(xiàn)判斷,但可以肯定的是,不管是+號(hào)還是#號(hào)作用于start狀態(tài),都會(huì)進(jìn)入done狀態(tài)。

第四篇:struts2代碼分析

1.Struts2架構(gòu)圖和請(qǐng)求處理流程

請(qǐng)求首先通過Filter chain,F(xiàn)ilter主要包括ActionContextCleanUp,它主要清理當(dāng)前線程的ActionContext和Dispatcher;FilterDispatcher主要通過AcionMapper來決定需要調(diào)用哪個(gè)Action。

ActionMapper取得了ActionMapping后,在Dispatcher的serviceAction方法里創(chuàng)建ActionProxy,ActionProxy創(chuàng)建ActionInvocation,然后ActionInvocation調(diào)用Interceptors,執(zhí)行Action本身,創(chuàng)建Result并返回,當(dāng)然,如果要在返回之前做些什么,可以實(shí)現(xiàn)PreResultListener。

2.Struts2部分類介紹

這部分從Struts2參考文檔中翻譯就可以了。

ActionMapper

ActionMapper其實(shí)是HttpServletRequest和Action調(diào)用請(qǐng)求的一個(gè)映射,它屏蔽了Action對(duì)于Request等java Servlet類的依賴。Struts2中它的默認(rèn)實(shí)現(xiàn)類是DefaultActionMapper,ActionMapper很大的用處可以根據(jù)自己的需要來設(shè)計(jì)url格式,它自己也有Restful的實(shí)現(xiàn),具體可以參考文檔的docs¥actionmapper.html。

ActionProxy&ActionInvocation

Action的一個(gè)代理,由ActionProxyFactory創(chuàng)建,它本身不包括Action實(shí)例,默認(rèn)實(shí)現(xiàn)DefaultActionProxy是由ActionInvocation持有Action實(shí)例。ActionProxy作用是如何取得Action,無論是本地還是遠(yuǎn)程。而ActionInvocation的作用是如何執(zhí)行Action,攔截器的功能就是在ActionInvocation中實(shí)現(xiàn)的。

ConfigurationProvider&Configuration

ConfigurationProvider就是Struts2中配置文件的解析器,Struts2中的配置文件主要是尤其實(shí)現(xiàn)類XmlConfigurationProvider及其子類StrutsXmlConfigurationProvider來解析。

3.Struts2請(qǐng)求流程

1、客戶端發(fā)送請(qǐng)求

2、請(qǐng)求先通過ActionContextCleanUp-->FilterDispatcher

3、FilterDispatcher通過ActionMapper來決定這個(gè)Request需要調(diào)用哪個(gè)Action

4、如果ActionMapper決定調(diào)用某個(gè)Action,F(xiàn)ilterDispatcher把請(qǐng)求的處理交給ActionProxy,這兒已經(jīng)轉(zhuǎn)到它的Delegate--Dispatcher來執(zhí)行

5、ActionProxy根據(jù)ActionMapping和ConfigurationManager找到需要調(diào)用的Action類

6、ActionProxy創(chuàng)建一個(gè)ActionInvocation的實(shí)例

7、ActionInvocation調(diào)用真正的Action,當(dāng)然這涉及到相關(guān)攔截器的調(diào)用

8、Action執(zhí)行完畢,ActionInvocation創(chuàng)建Result并返回,當(dāng)然,如果要在返回之前做些什么,可以實(shí)現(xiàn)PreResultListener。添加PreResultListener可以在Interceptor中實(shí)現(xiàn)。

首先強(qiáng)調(diào)一下struts2的線程程安全,在Struts2中大量采用ThreadLocal線程局部變量的方法來保證線程的安全,像Dispatcher等都是通過ThreadLocal來保存變量值,使得每個(gè)線程都有自己獨(dú)立的實(shí)例變量,互不相干.接下來就從Dispatcher開始看起,先看其構(gòu)造函數(shù):

//創(chuàng)建Dispatcher,此類是一個(gè)Delegate,它是真正完成根據(jù)url解析轉(zhuǎn)向,讀取對(duì)應(yīng)Action的地方

public Dispatcher(ServletContext servletContext, Map initParams){

this.servletContext = servletContext;

//配置在web.xml中的param參數(shù)

this.initParams = initParams;

}

//創(chuàng)建Dispatcher,此類是一個(gè)Delegate,它是真正完成根據(jù)url解析轉(zhuǎn)向,讀取對(duì)應(yīng)Action的地方

public Dispatcher(ServletContext servletContext, Map initParams){

this.servletContext = servletContext;

//配置在web.xml中的param參數(shù)

this.initParams = initParams;

}

我們?cè)倏丛贔ilterDispatcher創(chuàng)建Dispatcher的:

protected Dispatcher createDispatcher(FilterConfig filterConfig){

Map params = new HashMap();

for(Enumeration e = filterConfig.getInitParameterNames();e.hasMoreElements();){

String name =(String)e.nextElement();

String value = filterConfig.getInitParameter(name);

params.put(name, value);

}

都可以從FilterConfig中得到

return new Dispatcher(filterConfig.getServletContext(), params);

}

protected Dispatcher createDispatcher(FilterConfig filterConfig){

Map params = new HashMap();

for(Enumeration e = filterConfig.getInitParameterNames();e.hasMoreElements();){

String name =(String)e.nextElement();

String value = filterConfig.getInitParameter(name);

params.put(name, value);

}

都可以從FilterConfig中得到

return new Dispatcher(filterConfig.getServletContext(), params);

}

分七步載入各種配置屬性,都是通過ConfigurationProvider接口進(jìn)行的,這個(gè)接口提供init(),destroy(),register()等方法.將各種ConfigurationProvider初始化之后將實(shí)例添加到ConfigurationManager的List里面.最后通過循環(huán)調(diào)用List里的這些destroy(),register()等方法實(shí)現(xiàn)對(duì)配置文件的屬性進(jìn)行注冊(cè)和銷毀等功能.下面將分析這七層功夫是怎樣一步步練成的.首先是init_DefaultProperties()

創(chuàng)建Dispatcher之后,來看init()方法

init()方法是用來Load用戶配置文件,資源文件以及默認(rèn)的配置文件.主要分七步走,看下面注釋

public void init(){

if(configurationManager == null){

//設(shè)置ConfigurationManager的defaultFrameworkBeanName.//這里DEFAULT_BEAN_NAME為struts,這是xwork框架的內(nèi)容,Framework可以是xwork,struts,webwork等

configurationManager

=

new ConfigurationManager(BeanSelectionProvider.DEFAULT_BEAN_NAME);

}

//讀取properties信息,默認(rèn)的default.properties,init_DefaultProperties();// [1]

//讀取xml配置文件

init_TraditionalXmlConfigurations();// [2]

//讀取用戶自定義的struts.properties

init_LegacyStrutsProperties();// [3]

//自定義的configProviders

init_CustomConfigurationProviders();// [5]

//載入FilterDispatcher傳進(jìn)來的initParams

init_FilterInitParameters();// [6]

//將配置文件中的bean與具體的類映射

init_AliasStandardObjects();// [7]

//構(gòu)建一個(gè)用于依賴注射的Container對(duì)象

//在這里面會(huì)循環(huán)調(diào)用上面七個(gè)ConfigurationProvider的register方法

//其中的重點(diǎn)就是DefaultConfiguration的#reload()方法

Container container = init_PreloadConfiguration();

container.inject(this);

init_CheckConfigurationReloading(container);

init_CheckWebLogicWorkaround(container);

if(!dispatcherListeners.isEmpty()){

for(DispatcherListener l : dispatcherListeners){

l.dispatcherInitialized(this);

}

}

}

public void init(){

if(configurationManager == null){

//設(shè)置ConfigurationManager的defaultFrameworkBeanName.//這里DEFAULT_BEAN_NAME為struts,這是xwork框架的內(nèi)容,Framework可以是xwork,struts,webwork等

configurationManager

=

new ConfigurationManager(BeanSelectionProvider.DEFAULT_BEAN_NAME);

}

//讀取properties信息,默認(rèn)的default.properties,init_DefaultProperties();// [1]

//讀取xml配置文件

init_TraditionalXmlConfigurations();// [2]

//讀取用戶自定義的struts.properties

init_LegacyStrutsProperties();// [3]

//自定義的configProviders

init_CustomConfigurationProviders();// [5]

//載入FilterDispatcher傳進(jìn)來的initParams

init_FilterInitParameters();// [6]

//將配置文件中的bean與具體的類映射

init_AliasStandardObjects();// [7]

//構(gòu)建一個(gè)用于依賴注射的Container對(duì)象

//在這里面會(huì)循環(huán)調(diào)用上面七個(gè)ConfigurationProvider的register方法

//其中的重點(diǎn)就是DefaultConfiguration的#reload()方法

Container container = init_PreloadConfiguration();

container.inject(this);

init_CheckConfigurationReloading(container);

init_CheckWebLogicWorkaround(container);

if(!dispatcherListeners.isEmpty()){

for(DispatcherListener l : dispatcherListeners){

l.dispatcherInitialized(this);

}

}

}

分七步載入各種配置屬性,都是通過ConfigurationProvider接口進(jìn)行的,這個(gè)接口提供init(),destroy(),register()等方法.將各種ConfigurationProvider初始化之后將實(shí)例添加到ConfigurationManager的List里面.最后通過循環(huán)調(diào)用List里的這些destroy(),register()等方法實(shí)現(xiàn)對(duì)配置文件的屬性進(jìn)行注冊(cè)和銷毀等功能.下面將分析這七層功夫是怎樣一步步練成的.首先是init_DefaultProperties()

private void init_DefaultProperties(){

configurationManager.addConfigurationProvider(new DefaultPropertiesProvider());

}

接來看DefaultPropertiesProvider好了,DefaultPropertiesProvider實(shí)際上只是實(shí)現(xiàn)了register()方法

public void register(ContainerBuilder builder, LocatableProperties props)

throws ConfigurationException {

Settings defaultSettings = null;

try {

defaultSettings = new PropertiesSettings(“org/apache/struts2/default”);

} catch(Exception e){

throw

}

loadSettings(props, defaultSettings);

}

private void init_DefaultProperties(){

configurationManager.addConfigurationProvider(new DefaultPropertiesProvider());

}

接來看DefaultPropertiesProvider好了,DefaultPropertiesProvider實(shí)際上只是實(shí)現(xiàn)了register()方法

public void register(ContainerBuilder builder, LocatableProperties props)

throws ConfigurationException {

Settings defaultSettings = null;

try {

defaultSettings = new PropertiesSettings(“org/apache/struts2/default”);

} catch(Exception e){

new

ConfigurationException(“Could

not

find

or

error

in org/apache/struts2/default.properties”, e);

throw

}

new ConfigurationException(“Could not find or error in org/apache/struts2/default.properties”, e);

loadSettings(props, defaultSettings);

}

//PropertiesSettings構(gòu)造方法

//讀取org/apache/struts2/default.properties的配置信息,如果項(xiàng)目中需要覆蓋,可以在classpath里的struts.properties里覆寫

public PropertiesSettings(String name){

URL settingsUrl = ClassLoaderUtils.getResource(name + “.properties”, getClass());

if(settingsUrl == null){

LOG.debug(name + “.properties missing”);

settings = new LocatableProperties();

return;

}

settings

// Load settings

InputStream in = null;

try {

in = settingsUrl.openStream();

settings.load(in);

} catch(IOException e){

throw new StrutsException(“Could not load ” + name + “.properties:” + e, e);

} finally {

if(in!= null){

try {

=

new

LocatableProperties(new

LocationImpl(null, settingsUrl.toString()));

in.close();

} catch(IOException io){

LOG.warn(“Unable to close input stream”, io);

}

}

}

}

//loadSettings主要是將progerty的value和Locale從上面PropertiesSettings中取得并存放到LocatableProperties props

//這個(gè)props是register的一個(gè)入?yún)?protected void loadSettings(LocatableProperties props, final Settings settings){

// We are calling the impl methods to get around the single instance of Settings that is expected

for(Iterator i = settings.listImpl();i.hasNext();){

String name =(String)i.next();

props.setProperty(name, settings.getLocationImpl(name));

}

}

//PropertiesSettings構(gòu)造方法

//讀取org/apache/struts2/default.properties的配置信息,如果項(xiàng)目中需要覆蓋,可以在classpath里的struts.properties里覆寫

public PropertiesSettings(String name){

URL settingsUrl = ClassLoaderUtils.getResource(name + “.properties”, getClass());

if(settingsUrl == null){

LOG.debug(name + “.properties missing”);

settings = new LocatableProperties();

return;

}

settings =

new

LocatableProperties(new

LocationImpl(null, settingsUrl.toString()));

settings.getImpl(name),// Load settings

InputStream in = null;

try {

in = settingsUrl.openStream();

settings.load(in);

} catch(IOException e){

throw new StrutsException(“Could not load ” + name + “.properties:” + e, e);

} finally {

if(in!= null){

try {

in.close();

} catch(IOException io){

LOG.warn(“Unable to close input stream”, io);

}

}

}

}

//loadSettings主要是將progerty的value和Locale從上面PropertiesSettings中取得并存放到LocatableProperties props

//這個(gè)props是register的一個(gè)入?yún)?protected void loadSettings(LocatableProperties props, final Settings settings){

// We are calling the impl methods to get around the single instance of Settings that is expected

for(Iterator i = settings.listImpl();i.hasNext();){

String name =(String)i.next();

props.setProperty(name, settings.getLocationImpl(name));

}

}

再來看第二步:init_TraditionalXmlConfigurations()

private void init_TraditionalXmlConfigurations(){

settings.getImpl(name), //首先讀取web.xml中的config初始參數(shù)值

//如果

使

認(rèn)的DEFAULT_CONFIGURATION_PATHS:“struts-default.xml,struts-plugin.xml,struts.xml”,//這兒就可以看出為什么默認(rèn)的配置文件必須取名為這三個(gè)名稱了

//如果不想使用默認(rèn)的名稱,直接在web.xml中配置config初始參數(shù)即可

String configPaths = initParams.get(“config”);

if(configPaths == null){

configPaths = DEFAULT_CONFIGURATION_PATHS;

}

String[] files = configPaths.split(“¥¥s*[,]¥¥s*”);

for(String file : files){

if(file.endsWith(“.xml”)){

if(“xwork.xml”.equals(file)){

//XmlConfigurationProvider負(fù)責(zé)解析xwork.xml

configurationManager.addConfigurationProvider(new XmlConfigurationProvider(file, false));

} else {

//其它xml都是由StrutsXmlConfigurationProvider來解析

configurationManager.addConfigurationProvider(new StrutsXmlConfigurationProvider(file, false, servletContext));

}

} else {

throw new IllegalArgumentException(“Invalid configuration file name”);

}

}

}

private void init_TraditionalXmlConfigurations(){

//首先讀取web.xml中的config初始參數(shù)值

//如果

使

認(rèn)的DEFAULT_CONFIGURATION_PATHS:“struts-default.xml,struts-plugin.xml,struts.xml”,//這兒就可以看出為什么默認(rèn)的配置文件必須取名為這三個(gè)名稱了

//如果不想使用默認(rèn)的名稱,直接在web.xml中配置config初始參數(shù)即可

String configPaths = initParams.get(“config”);

if(configPaths == null){

configPaths = DEFAULT_CONFIGURATION_PATHS;

}

String[] files = configPaths.split(“¥¥s*[,]¥¥s*”);

for(String file : files){

if(file.endsWith(“.xml”)){

if(“xwork.xml”.equals(file)){

//XmlConfigurationProvider負(fù)責(zé)解析xwork.xml

configurationManager.addConfigurationProvider(new XmlConfigurationProvider(file, false));

} else {

//其它xml都是由StrutsXmlConfigurationProvider來解析

configurationManager.addConfigurationProvider(new StrutsXmlConfigurationProvider(file, false, servletContext));

}

} else {

throw new IllegalArgumentException(“Invalid configuration file name”);

}

}

}

對(duì)于其它配置文件只用接口。

類XmlConfigurationProvider負(fù)責(zé)配置文件的讀取和解析,首先通過init()中的loadDocuments(configFileName);利用DomHelper中的

public static Document parse(InputSource inputSource, Map dtdMappings)將configFileName配置文件通過SAX解析方式按照DtdMappings解析成Document對(duì)象.然后通過Provider的register()方法加載“bean”和“constant”屬性,再通過loadPackages()加載package及package中的屬性

addAction()方法負(fù)責(zé)讀取標(biāo)簽,并將數(shù)據(jù)保存在ActionConfig中; addResultTypes()方法負(fù)責(zé)將標(biāo)簽轉(zhuǎn)化為ResultTypeConfig對(duì)象; loadInterceptors()方法負(fù)責(zé)將標(biāo)簽轉(zhuǎn)化為InterceptorConfi對(duì)象;

loadInterceptorStack()方法負(fù)責(zé)將標(biāo)簽轉(zhuǎn)化為InterceptorStackConfig對(duì)象;

StrutsXmlConfigurationProvider,此類繼承XmlConfigurationProvider,而XmlConfigurationProvider又實(shí)現(xiàn)ConfigurationProviderloadInterceptorStacks()方法負(fù)責(zé)將標(biāo)簽轉(zhuǎn)化成InterceptorStackConfig對(duì)象。

而上面的方法最終會(huì)被addPackage()方法調(diào)用,addPackage又會(huì)被Provider的loadPackages()調(diào)用,將所讀取到的數(shù)據(jù)匯集到PackageConfig對(duì)象中。

protected PackageConfig

addPackage(Element

packageElement)

throws ConfigurationException {

PackageConfig.Builder newPackage = buildPackageContext(packageElement);

if(newPackage.isNeedsRefresh()){

return newPackage.build();

}

// add result types(and default result)to this package

addResultTypes(newPackage, packageElement);

// load the interceptors and interceptor stacks for this package

loadInterceptors(newPackage, packageElement);

// load the default interceptor reference for this package

loadDefaultInterceptorRef(newPackage, packageElement);

// load the default class ref for this package

loadDefaultClassRef(newPackage, packageElement);

// load the global result list for this package

loadGlobalResults(newPackage, packageElement);

// load the global exception handler list for this package

loadGobalExceptionMappings(newPackage, packageElement);

// get actions

NodeList actionList = packageElement.getElementsByTagName(“action”);

for(int i = 0;i < actionList.getLength();i++){

Element actionElement =(Element)actionList.item(i);

addAction(actionElement, newPackage);

}

// load the default action reference for this package

loadDefaultActionRef(newPackage, packageElement);

PackageConfig cfg = newPackage.build();

configuration.addPackageConfig(cfg.getName(), cfg);

return cfg;

}

loadConfigurationFiles解析讀取xml中的內(nèi)容

private List

loadConfigurationFiles(String

fileName,Element includeElement){

...//通過DomHelper調(diào)用SAX進(jìn)行解析xml

doc = DomHelper.parse(in, dtdMappings);

...Element rootElement = doc.getDocumentElement();

NodeList children = rootElement.getChildNodes();

int childSize = children.getLength();

for(int i = 0;i < childSize;i++){

Node childNode = children.item(i);

if(childNode instanceof Element){

Element child =(Element)childNode;

final String nodeName = child.getNodeName();

if(“include”.equals(nodeName)){

String includeFileName = child.getAttribute(“file”);

//解析每個(gè)action配置是,對(duì)于include文件可以使用通配符*來進(jìn)行配置

//如Struts.xml中可配置成

if(includeFileName.indexOf('*')!=-1){

ClassPathFinder wildcardFinder = new ClassPathFinder();

wildcardFinder.setPattern(includeFileName);

Vector wildcardMatches = wildcardFinder.findMatches();

for(String match : wildcardMatches){

//遞歸Load子file中的

docs.addAll(loadConfigurationFiles(match, child));

}

} else {

docs.addAll(loadConfigurationFiles(includeFileName, child));

}

}

}

}

docs.add(doc);

loadedFileUrls.add(url.toString());

...return docs;

}

首先強(qiáng)調(diào)一下struts2的線程程安全,在Struts2中大量采用ThreadLocal線程局部變量的方法來保證線程的安全,像Dispatcher等都是通過ThreadLocal來保存變量值,使得每個(gè)線程都有自己獨(dú)立的實(shí)例變量,互不相干.接下來就從Dispatcher開始看起,先看其構(gòu)造函數(shù):

//創(chuàng)建Dispatcher,此類是一個(gè)Delegate,它是真正完成根據(jù)url解析轉(zhuǎn)向,讀取對(duì)應(yīng)Action的地方

public Dispatcher(ServletContext servletContext, Map initParams){

this.servletContext = servletContext;

//配置在web.xml中的param參數(shù)

this.initParams = initParams;

}

//創(chuàng)建Dispatcher,此類是一個(gè)Delegate,它是真正完成根據(jù)url解析轉(zhuǎn)向,讀取對(duì)應(yīng)Action的地方

public Dispatcher(ServletContext servletContext, Map initParams){

this.servletContext = servletContext;

//配置在web.xml中的param參數(shù)

this.initParams = initParams;

}

我們?cè)倏丛贔ilterDispatcher創(chuàng)建Dispatcher的:

protected Dispatcher createDispatcher(FilterConfig filterConfig){

Map params = new HashMap();

for(Enumeration e = filterConfig.getInitParameterNames();e.hasMoreElements();){

String name =(String)e.nextElement();

String value = filterConfig.getInitParameter(name);

params.put(name, value);

}

都可以從FilterConfig中得到

return new Dispatcher(filterConfig.getServletContext(), params);

}

protected Dispatcher createDispatcher(FilterConfig filterConfig){

Map params = new HashMap();

for(Enumeration e = filterConfig.getInitParameterNames();e.hasMoreElements();){

String name =(String)e.nextElement();

String value = filterConfig.getInitParameter(name);

params.put(name, value);

}

都可以從FilterConfig中得到

return new Dispatcher(filterConfig.getServletContext(), params);

}

分七步載入各種配置屬性,都是通過ConfigurationProvider接口進(jìn)行的,這個(gè)接口提供init(),destroy(),register()等方法.將各種ConfigurationProvider初始化之后將實(shí)例添加到ConfigurationManager的List里面.最后通過循環(huán)調(diào)用List里的這些destroy(),register()等方法實(shí)現(xiàn)對(duì)配置文件的屬性進(jìn)行注冊(cè)和銷毀等功能.下面將分析這七層功夫是怎樣一步步練成的.首先是init_DefaultProperties()

創(chuàng)建Dispatcher之后,來看init()方法

init()方法是用來Load用戶配置文件,資源文件以及默認(rèn)的配置文件.主要分七步走,看下面注釋

public void init(){

if(configurationManager == null){

//設(shè)置ConfigurationManager的defaultFrameworkBeanName.//這里DEFAULT_BEAN_NAME為struts,這是xwork框架的內(nèi)容,Framework可以是xwork,struts,webwork等

configurationManager = ConfigurationManager(BeanSelectionProvider.DEFAULT_BEAN_NAME);

}

//讀取properties信息,默認(rèn)的default.properties,init_DefaultProperties();// [1]

//讀取xml配置文件

init_TraditionalXmlConfigurations();// [2]

//讀取用戶自定義的struts.properties

init_LegacyStrutsProperties();// [3]

//自定義的configProviders

init_CustomConfigurationProviders();// [5]

//載入FilterDispatcher傳進(jìn)來的initParams

init_FilterInitParameters();// [6]

//將配置文件中的bean與具體的類映射

init_AliasStandardObjects();// [7]

//構(gòu)建一個(gè)用于依賴注射的Container對(duì)象

//在這里面會(huì)循環(huán)調(diào)用上面七個(gè)ConfigurationProvider的register方法

//其中的重點(diǎn)就是DefaultConfiguration的#reload()方法

Container container = init_PreloadConfiguration();

container.inject(this);

init_CheckConfigurationReloading(container);

init_CheckWebLogicWorkaround(container);

if(!dispatcherListeners.isEmpty()){

for(DispatcherListener l : dispatcherListeners){

l.dispatcherInitialized(this);

}

}

new

}

public void init(){

if(configurationManager == null){

//設(shè)置ConfigurationManager的defaultFrameworkBeanName.//這里DEFAULT_BEAN_NAME為struts,這是xwork框架的內(nèi)容,Framework可以是xwork,struts,webwork等

configurationManager = ConfigurationManager(BeanSelectionProvider.DEFAULT_BEAN_NAME);

}

//讀取properties信息,默認(rèn)的default.properties,init_DefaultProperties();// [1]

//讀取xml配置文件

init_TraditionalXmlConfigurations();// [2]

//讀取用戶自定義的struts.properties

init_LegacyStrutsProperties();// [3]

//自定義的configProviders

init_CustomConfigurationProviders();// [5]

//載入FilterDispatcher傳進(jìn)來的initParams

init_FilterInitParameters();// [6]

//將配置文件中的bean與具體的類映射

init_AliasStandardObjects();// [7]

//構(gòu)建一個(gè)用于依賴注射的Container對(duì)象

//在這里面會(huì)循環(huán)調(diào)用上面七個(gè)ConfigurationProvider的register方法

//其中的重點(diǎn)就是DefaultConfiguration的#reload()方法

Container container = init_PreloadConfiguration();

container.inject(this);

init_CheckConfigurationReloading(container);

init_CheckWebLogicWorkaround(container);

if(!dispatcherListeners.isEmpty()){

for(DispatcherListener l : dispatcherListeners){

l.dispatcherInitialized(this);

}

}

new

}

分七步載入各種配置屬性,都是通過ConfigurationProvider接口進(jìn)行的,這個(gè)接口提供init(),destroy(),register()等方法.將各種ConfigurationProvider初始化之后將實(shí)例添加到ConfigurationManager的List里面.最后通過循環(huán)調(diào)用List里的這些destroy(),register()等方法實(shí)現(xiàn)對(duì)配置文件的屬性進(jìn)行注冊(cè)和銷毀等功能.下面將分析這七層功夫是怎樣一步步練成的.首先是init_DefaultProperties()

private void init_DefaultProperties(){

configurationManager.addConfigurationProvider(new DefaultPropertiesProvider());

}

接來看DefaultPropertiesProvider好了,DefaultPropertiesProvider實(shí)際上只是實(shí)現(xiàn)了register()方法

public void register(ContainerBuilder builder, LocatableProperties props)

throws ConfigurationException {

Settings defaultSettings = null;

try {

defaultSettings = new PropertiesSettings(“org/apache/struts2/default”);

} catch(Exception e){

throw

}

loadSettings(props, defaultSettings);

}

private void init_DefaultProperties(){

configurationManager.addConfigurationProvider(new DefaultPropertiesProvider());

}

接來看DefaultPropertiesProvider好了,DefaultPropertiesProvider實(shí)際上只是實(shí)現(xiàn)了new

ConfigurationException(“Could

not

find

or

error

in org/apache/struts2/default.properties”, e);

register()方法

public void register(ContainerBuilder builder, LocatableProperties props)

throws ConfigurationException {

Settings defaultSettings = null;

try {

defaultSettings = new PropertiesSettings(“org/apache/struts2/default”);

} catch(Exception e){

throw

}

loadSettings(props, defaultSettings);

}

//PropertiesSettings構(gòu)造方法

//讀取org/apache/struts2/default.properties的配置信息,如果項(xiàng)目中需要覆蓋,可以在classpath里的struts.properties里覆寫

public PropertiesSettings(String name){

URL settingsUrl = ClassLoaderUtils.getResource(name + “.properties”, getClass());

if(settingsUrl == null){

LOG.debug(name + “.properties missing”);

settings = new LocatableProperties();

return;

}

settings

// Load settings

InputStream in = null;

try {

=

new

LocatableProperties(new

LocationImpl(null, settingsUrl.toString()));

new

ConfigurationException(“Could

not

find

or

error

in org/apache/struts2/default.properties”, e);

in = settingsUrl.openStream();

settings.load(in);

} catch(IOException e){

throw new StrutsException(“Could not load ” + name + “.properties:” + e, e);

} finally {

if(in!= null){

try {

in.close();

} catch(IOException io){

LOG.warn(“Unable to close input stream”, io);

}

}

}

}

//loadSettings主要是將progerty的value和Locale從上面PropertiesSettings中取得并存放到LocatableProperties props

//這個(gè)props是register的一個(gè)入?yún)?protected void loadSettings(LocatableProperties props, final Settings settings){

// We are calling the impl methods to get around the single instance of Settings that is expected

for(Iterator i = settings.listImpl();i.hasNext();){

String name =(String)i.next();

props.setProperty(name, settings.getLocationImpl(name));

}

}

//PropertiesSettings構(gòu)造方法

//讀取org/apache/struts2/default.properties的配置信息,如果項(xiàng)目中需要覆蓋,可以在classpath里的struts.properties里覆寫

public PropertiesSettings(String name){

URL settingsUrl = ClassLoaderUtils.getResource(name + “.properties”, getClass());

settings.getImpl(name),if(settingsUrl == null){

LOG.debug(name + “.properties missing”);

settings = new LocatableProperties();

return;

}

settings

// Load settings

InputStream in = null;

try {

in = settingsUrl.openStream();

settings.load(in);

} catch(IOException e){

throw new StrutsException(“Could not load ” + name + “.properties:” + e, e);

} finally {

if(in!= null){

try {

in.close();

} catch(IOException io){

LOG.warn(“Unable to close input stream”, io);

}

}

}

}

//loadSettings主要是將progerty的value和Locale從上面PropertiesSettings中取得并存放到LocatableProperties props

//這個(gè)props是register的一個(gè)入?yún)?protected void loadSettings(LocatableProperties props, final Settings settings){

// We are calling the impl methods to get around the single instance of Settings that is expected

for(Iterator i = settings.listImpl();i.hasNext();){

String name =(String)i.next();

=

new

LocatableProperties(new

LocationImpl(null, settingsUrl.toString()));

props.setProperty(name, settings.getLocationImpl(name));

}

}

再來看第二步:init_TraditionalXmlConfigurations()

private void init_TraditionalXmlConfigurations(){

//首先讀取web.xml中的config初始參數(shù)值

//如果

使

settings.getImpl(name),用默認(rèn)的DEFAULT_CONFIGURATION_PATHS:“struts-default.xml,struts-plugin.xml,struts.xml”,//這兒就可以看出為什么默認(rèn)的配置文件必須取名為這三個(gè)名稱了

//如果不想使用默認(rèn)的名稱,直接在web.xml中配置config初始參數(shù)即可

String configPaths = initParams.get(“config”);

if(configPaths == null){

configPaths = DEFAULT_CONFIGURATION_PATHS;

}

String[] files = configPaths.split(“¥¥s*[,]¥¥s*”);

for(String file : files){

if(file.endsWith(“.xml”)){

if(“xwork.xml”.equals(file)){

//XmlConfigurationProvider負(fù)責(zé)解析xwork.xml

configurationManager.addConfigurationProvider(new XmlConfigurationProvider(file, false));

} else {

//其它xml都是由StrutsXmlConfigurationProvider來解析

configurationManager.addConfigurationProvider(new StrutsXmlConfigurationProvider(file, false, servletContext));

}

} else {

throw new IllegalArgumentException(“Invalid configuration file name”);

}

}

}

private void init_TraditionalXmlConfigurations(){

//首先讀取web.xml中的config初始參數(shù)值

//如果

使

認(rèn)的DEFAULT_CONFIGURATION_PATHS:“struts-default.xml,struts-plugin.xml,struts.xml”,//這兒就可以看出為什么默認(rèn)的配置文件必須取名為這三個(gè)名稱了

//如果不想使用默認(rèn)的名稱,直接在web.xml中配置config初始參數(shù)即可

String configPaths = initParams.get(“config”);

if(configPaths == null){

configPaths = DEFAULT_CONFIGURATION_PATHS;

}

String[] files = configPaths.split(“¥¥s*[,]¥¥s*”);

for(String file : files){

if(file.endsWith(“.xml”)){

if(“xwork.xml”.equals(file)){

//XmlConfigurationProvider負(fù)責(zé)解析xwork.xml

configurationManager.addConfigurationProvider(new XmlConfigurationProvider(file, false));

} else {

//其它xml都是由StrutsXmlConfigurationProvider來解析

configurationManager.addConfigurationProvider(new StrutsXmlConfigurationProvider(file, false, servletContext));

}

} else {

throw new IllegalArgumentException(“Invalid configuration file name”);

}

}

}

對(duì)于其它配置文件只用接口。

類XmlConfigurationProvider負(fù)責(zé)配置文件的讀取和解析,首先通過init()中的loadDocuments(configFileName);利用DomHelper中的

public static Document parse(InputSource inputSource, Map dtdMappings)將configFileName配置文件通過SAX解析方式按照DtdMappings解析成StrutsXmlConfigurationProvider,此類繼承XmlConfigurationProvider,而XmlConfigurationProvider又實(shí)現(xiàn)ConfigurationProviderDocument對(duì)象.然后通過Provider的register()方法加載“bean”和“constant”屬性,再通過loadPackages()加載package及package中的屬性

addAction()方法負(fù)責(zé)讀取標(biāo)簽,并將數(shù)據(jù)保存在ActionConfig中; addResultTypes()方法負(fù)責(zé)將標(biāo)簽轉(zhuǎn)化為ResultTypeConfig對(duì)象; loadInterceptors()方法負(fù)責(zé)將標(biāo)簽轉(zhuǎn)化為InterceptorConfi對(duì)象;

loadInterceptorStack()方法負(fù)責(zé)將標(biāo)簽轉(zhuǎn)化為InterceptorStackConfig對(duì)象;

loadInterceptorStacks()方法負(fù)責(zé)將標(biāo)簽轉(zhuǎn)化成InterceptorStackConfig對(duì)象。

而上面的方法最終會(huì)被addPackage()方法調(diào)用,addPackage又會(huì)被Provider的loadPackages()調(diào)用,將所讀取到的數(shù)據(jù)匯集到PackageConfig對(duì)象中。

protected PackageConfig

addPackage(Element

packageElement)

throws ConfigurationException {

PackageConfig.Builder newPackage = buildPackageContext(packageElement);

if(newPackage.isNeedsRefresh()){

return newPackage.build();

}

// add result types(and default result)to this package

addResultTypes(newPackage, packageElement);

// load the interceptors and interceptor stacks for this package

loadInterceptors(newPackage, packageElement);

// load the default interceptor reference for this package

loadDefaultInterceptorRef(newPackage, packageElement);

// load the default class ref for this package

loadDefaultClassRef(newPackage, packageElement);

// load the global result list for this package

loadGlobalResults(newPackage, packageElement);

// load the global exception handler list for this package

loadGobalExceptionMappings(newPackage, packageElement);

// get actions

NodeList actionList = packageElement.getElementsByTagName(“action”);

for(int i = 0;i < actionList.getLength();i++){

Element actionElement =(Element)actionList.item(i);

addAction(actionElement, newPackage);

}

// load the default action reference for this package

loadDefaultActionRef(newPackage, packageElement);

PackageConfig cfg = newPackage.build();

configuration.addPackageConfig(cfg.getName(), cfg);

return cfg;

}

loadConfigurationFiles解析讀取xml中的內(nèi)容

private List

loadConfigurationFiles(String

fileName, includeElement){

...//通過DomHelper調(diào)用SAX進(jìn)行解析xml

doc = DomHelper.parse(in, dtdMappings);

...Element rootElement = doc.getDocumentElement();

NodeList children = rootElement.getChildNodes();

int childSize = children.getLength();

for(int i = 0;i < childSize;i++){

Node childNode = children.item(i);

if(childNode instanceof Element){

Element child =(Element)childNode;

final String nodeName = child.getNodeName();

if(“include”.equals(nodeName)){

String includeFileName = child.getAttribute(“file”);

//解析每個(gè)action配置是,對(duì)于include文件可以使用通配符*來進(jìn)行配置

//如Struts.xml中可配置成

if(includeFileName.indexOf('*')!=-1){

ClassPathFinder wildcardFinder = new ClassPathFinder();

wildcardFinder.setPattern(includeFileName);

Element

Vector wildcardMatches = wildcardFinder.findMatches();

for(String match : wildcardMatches){

//遞歸Load子file中的

docs.addAll(loadConfigurationFiles(match, child));

}

} else {

docs.addAll(loadConfigurationFiles(includeFileName, child));

}

}

}

}

docs.add(doc);

loadedFileUrls.add(url.toString());

...return docs;

}

接下來第三步:init_LegacyStrutsProperties()調(diào)用的是調(diào)用的是LegacyPropertiesConfigurationProvider 通過比較前

DefaultPropertiesProvider

調(diào)

用的是LegacyPropertiesConfigurationProvider.發(fā)現(xiàn)DefaultPropertiesProvider繼承自后者,但重寫了register()方法,主要是生成PropertiesSetting的不同,前者是根據(jù)org/apache/struts2/default.properties 后者是根據(jù)struts.properties 我們展開register()中的Settings.getInstance(),最后是調(diào)用getDefaultInstance()

private static Settings getDefaultInstance(){

if(defaultImpl == null){

// Create bootstrap implementation

//不帶參數(shù)的DefaultSettings(),區(qū)別與DefaultPropertiesProvider中直接帶default.properties參數(shù)

//不帶參數(shù)就是默認(rèn)為struts.propertes,并且加載struts.custom.properties所定義的properties文件

defaultImpl = new DefaultSettings();

// Create default implementation

try {

//STRUTS_CONFIGURATION為:struts.configuration

//在struts.proterties中查找struts.configuration的值,這個(gè)值必須是org.apache.struts2.config.Configuration接口的實(shí)現(xiàn)類

//所以我有個(gè)困惑就是在下面的轉(zhuǎn)換當(dāng)中怎么將Configuration轉(zhuǎn)換成Setting類型的...//這一點(diǎn)先放下了,有時(shí)間再研究

String className = get(StrutsConstants.STRUTS_CONFIGURATION);

if(!className.equals(defaultImpl.getClass().getName())){

try {

// singleton instances shouldn't be built accessing request or session-specific context data

defaultImpl oader().loadClass(className), null);

} catch(Exception e){

LOG.error(“Settings:

}

}

} catch(IllegalArgumentException ex){

// ignore

}

private static Settings getDefaultInstance(){

if(defaultImpl == null){

// Create bootstrap implementation

//不帶參數(shù)的DefaultSettings(),區(qū)別與DefaultPropertiesProvider中直接帶default.properties參數(shù)

//不帶參數(shù)就是默認(rèn)為struts.propertes,并且加載struts.custom.properties所定義的properties文件

defaultImpl = new DefaultSettings();

// Create default implementation

try {

//STRUTS_CONFIGURATION為:struts.configuration

//在struts.proterties中查找struts.configuration的值,這個(gè)值必須是

Could

not

instantiate

the struts.configuration object, substituting the default implementation.”, e);

=

(Settings)ObjectFactory.getObjectFactory().buildBean(Thread.currentThread().getContextClassLorg.apache.struts2.config.Configuration接口的實(shí)現(xiàn)類

//所以我有個(gè)困惑就是在下面的轉(zhuǎn)換當(dāng)中怎么將Configuration轉(zhuǎn)換成Setting類型的...//這一點(diǎn)先放下了,有時(shí)間再研究

String className = get(StrutsConstants.STRUTS_CONFIGURATION);

if(!className.equals(defaultImpl.getClass().getName())){

try {

// singleton instances shouldn't be built accessing request or session-specific context data

defaultImpl oader().loadClass(className), null);

} catch(Exception e){

LOG.error(“Settings:

}

}

} catch(IllegalArgumentException ex){

// ignore

}

在2.1.6中去掉了第四步:init_ZeroConfiguration();第五步是自定義的configProviders

private void init_CustomConfigurationProviders(){

//從這里可以看到可以將自定義的Provider定義在web.xml中FilterDispatcher的param中:configProviders

String configProvs = initParams.get(”configProviders“);

if(configProvs!= null){

String[] classes = configProvs.split(”¥¥s*[,]¥¥s*“);

for(String cname : classes){

try {

Class cls = ClassLoaderUtils.loadClass(cname, this.getClass());

ConfigurationProvider(ConfigurationProvider)cls.newInstance();

configurationManager.addConfigurationProvider(prov);

prov

=

Could

not

instantiate

the struts.configuration object, substituting the default implementation.”, e);

=

(Settings)ObjectFactory.getObjectFactory().buildBean(Thread.currentThread().getContextClassL

}

...}

}

}

private void init_CustomConfigurationProviders(){

//從這里可以看到可以將自定義的Provider定義在web.xml中FilterDispatcher的param中:configProviders

String configProvs = initParams.get(“configProviders”);

if(configProvs!= null){

String[] classes = configProvs.split(“¥¥s*[,]¥¥s*”);

for(String cname : classes){

try {

Class cls = ClassLoaderUtils.loadClass(cname, this.getClass());

ConfigurationProvider(ConfigurationProvider)cls.newInstance();

configurationManager.addConfigurationProvider(prov);

}

...}

}

}

第六步:init_FilterInitParameters

//從這里可以看出struts.properties中的屬性不僅可以在struts.xml中以constant形式定義,而且可以在FilterDispatcher的param中定義

private void init_FilterInitParameters(){

configurationManager.addConfigurationProvider(new ConfigurationProvider(){

public void destroy(){}

public

void

init(Configuration

configuration)

throws ConfigurationException {}

public void loadPackages()throws ConfigurationException {}

public boolean needsReload(){ return false;}

prov

=

public void register(ContainerBuilder builder, LocatableProperties props)throws ConfigurationException {

props.putAll(initParams);//在這里實(shí)現(xiàn)滴~

}

});

}

//從這里可以看出struts.properties中的屬性不僅可以在struts.xml中以constant形式定義,而且可以在FilterDispatcher的param中定義

private void init_FilterInitParameters(){

configurationManager.addConfigurationProvider(new ConfigurationProvider(){

public void destroy(){}

public

void

init(Configuration

configuration)

throws ConfigurationException {}

public void loadPackages()throws ConfigurationException {}

public boolean needsReload(){ return false;}

public void register(ContainerBuilder builder, LocatableProperties props)throws ConfigurationException {

props.putAll(initParams);//在這里實(shí)現(xiàn)滴~

}

});

}

第七步:init_AliasStandardObjects,使用BeanSelectionProvider 這是將配置文件中定義的與實(shí)際的類相映射,就是注入bean的依賴關(guān)系,這部分以后有時(shí)候再研究Container

接下來是看怎樣調(diào)用這些ConfigurationProviders 展開init_PreloadConfiguration()

private Container init_PreloadConfiguration(){

Configuration config = configurationManager.getConfiguration();

Container container = config.getContainer();

boolean reloadi18n = Boolean.valueOf(container.getInstance(String.class, StrutsConstants.STRUTS_I18N_RELOAD));

LocalizedTextUtil.setReloadBundles(reloadi18n);

return container;

}

//再看getConfiguration()

public synchronized Configuration getConfiguration(){

if(configuration == null){

setConfiguration(new DefaultConfiguration(defaultFrameworkBeanName));

try {

//重點(diǎn)就是這個(gè)reloadContainer

configuration.reloadContainer(getContainerProviders());

} catch(ConfigurationException e){

setConfiguration(null);

throw new ConfigurationException(“Unable to load configuration.”, e);

}

} else {

conditionalReload();

}

return configuration;

}

private Container init_PreloadConfiguration(){

Configuration config = configurationManager.getConfiguration();

Container container = config.getContainer();

boolean reloadi18n

=

Boolean.valueOf(container.getInstance(String.class, StrutsConstants.STRUTS_I18N_RELOAD));

LocalizedTextUtil.setReloadBundles(reloadi18n);

return container;

}

//再看getConfiguration()

public synchronized Configuration getConfiguration(){

if(configuration == null){

setConfiguration(new DefaultConfiguration(defaultFrameworkBeanName));

try {

//重點(diǎn)就是這個(gè)reloadContainer

configuration.reloadContainer(getContainerProviders());

} catch(ConfigurationException e){

setConfiguration(null);

throw new ConfigurationException(“Unable to load configuration.”, e);

}

} else {

conditionalReload();

}

return configuration;

}

展開DefaultConfiguration中的reloadContainer

public synchronized List

reloadContainer(List providers)throws ConfigurationException {

packageContexts.clear();

loadedFileNames.clear();

List

packageProviders = new ArrayList

();

//Struts2(xwork2)用Container來完成依賴注入的功能

//首先初始化一個(gè)ContainerBuilder,再由builder來保存接口與實(shí)現(xiàn)類或工廠類的對(duì)應(yīng)關(guān)系

//然后通過builder.create(boolean)方法產(chǎn)生container

//由container.getInstance(Class);就可以得到接口的實(shí)現(xiàn)實(shí)例了

//這一部分比較復(fù)雜,后面研究完成了,會(huì)單獨(dú)拿出來講,這里先弄清楚Xwork依賴注入的實(shí)現(xiàn)步驟就可以了

ContainerProperties props = new ContainerProperties();

ContainerBuilder builder = new ContainerBuilder();

for(final ContainerProvider containerProvider : providers)

{

//循環(huán)調(diào)用ConfigurationProvider的init和register方法,明白了吧,在這里統(tǒng)一循環(huán)調(diào)用

containerProvider.init(this);

containerProvider.register(builder, props);

}

props.setConstants(builder);

//注入依賴關(guān)系,在這里并不產(chǎn)生實(shí)例

builder.factory(Configuration.class, new Factory(){

public Configuration create(Context context)throws Exception {

return DefaultConfiguration.this;

}

});

ActionContext oldContext = ActionContext.getContext();

try {

// Set the bootstrap container for the purposes of factory creation

Container bootstrap = createBootstrapContainer();

setContext(bootstrap);

//create已經(jīng)注入依賴關(guān)系的Container

container = builder.create(false);

setContext(container);

objectFactory = container.getInstance(ObjectFactory.class);

// Process the configuration providers first

for(final ContainerProvider containerProvider : providers)

{

if(containerProvider instanceof PackageProvider){

container.inject(containerProvider);

//調(diào)用PackageProvider的loadPackages()方法,這里主要是針對(duì)XmlConfigurationProvider和StrutsXmlConfigurationProvider

((PackageProvider)containerProvider).loadPackages();

packageProviders.add((PackageProvider)containerProvider);

}

}

// Then process any package providers from the plugins

Set

packageProviderNames

= container.getInstanceNames(PackageProvider.class);

if(packageProviderNames!= null){

for(String name : packageProviderNames){

PackageProvider

provider.init(this);

provider.loadPackages();

packageProviders.add(provider);

}

}

rebuildRuntimeConfiguration();

} finally {

if(oldContext == null){

ActionContext.setContext(null);

}

}

return packageProviders;

}

Dispatcher已經(jīng)在之前講過,這就好辦了。FilterDispatcher是Struts2的核心控制器,首先看一下init()方法。

public void init(FilterConfig filterConfig)throws ServletException {

try {

this.filterConfig = filterConfig;

initLogging();

//創(chuàng)建dispatcher,前面都已經(jīng)講過啰

dispatcher = createDispatcher(filterConfig);

dispatcher.init();

//注入將FilterDispatcher中的變量通過container注入,如下面的staticResourceLoader

dispatcher.getContainer().inject(this);

//StaticContentLoader在BeanSelectionProvider中已經(jīng)被注入了依賴關(guān)系:DefaultStaticContentLoader

//可以在struts-default.xml中的可以找到

staticResourceLoader.setHostConfig(new FilterHostConfig(filterConfig));

} finally {

provider

= container.getInstance(PackageProvider.class, name);

ActionContext.setContext(null);

}

}

public void init(FilterConfig filterConfig)throws ServletException {

try {

this.filterConfig = filterConfig;

initLogging();

//創(chuàng)建dispatcher,前面都已經(jīng)講過啰

dispatcher = createDispatcher(filterConfig);

dispatcher.init();

//注入將FilterDispatcher中的變量通過container注入,如下面的staticResourceLoader

dispatcher.getContainer().inject(this);

//StaticContentLoader在BeanSelectionProvider中已經(jīng)被注入了依賴關(guān)系:DefaultStaticContentLoader

//可以在struts-default.xml中的可以找到

staticResourceLoader.setHostConfig(new FilterHostConfig(filterConfig));

} finally {

ActionContext.setContext(null);

}

}

//下面來看DefaultStaticContentLoader的setHostConfig

public void setHostConfig(HostConfig filterConfig){

//讀取初始參數(shù)

pakages,調(diào)用

parse(),解析成類似/org/apache/struts2/static,/template的數(shù)組

String param = filterConfig.getInitParameter(“packages”);

//“org.apache.struts2.static org.apache.struts2.interceptor.debugging static”

String packages = getAdditionalPackages();

if(param!= null){

packages = param + “ ” + packages;

}

this.pathPrefixes = parse(packages);

initLogging(filterConfig);

}

template //下面來看DefaultStaticContentLoader的setHostConfig

public void setHostConfig(HostConfig filterConfig){

//讀取初始參數(shù)

pakages,調(diào)用

parse(),解析成類似/org/apache/struts2/static,/template的數(shù)組

String param = filterConfig.getInitParameter(“packages”);

//“org.apache.struts2.static org.apache.struts2.interceptor.debugging static”

String packages = getAdditionalPackages();

if(param!= null){

packages = param + “ ” + packages;

}

this.pathPrefixes = parse(packages);

initLogging(filterConfig);

}

現(xiàn)在回去doFilter的方法,每當(dāng)有一個(gè)Request,都會(huì)調(diào)用這些Filters的doFilter方法

public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)throws IOException, ServletException {

HttpServletRequest request =(HttpServletRequest)req;

HttpServletResponse response =(HttpServletResponse)res;

ServletContext servletContext = getServletContext();

String timerKey = “FilterDispatcher_doFilter: ”;

try {

// FIXME: this should be refactored better to not duplicate work with the action invocation

//先看看ValueStackFactory所注入的實(shí)現(xiàn)類OgnlValueStackFactory

//new OgnlValueStack

ValueStack

stack

= dispatcher.getContainer().getInstance(ValueStackFactory.class).createValueStack();

ActionContext ctx = new ActionContext(stack.getContext());

ActionContext.setContext(ctx);

template

UtilTimerStack.push(timerKey);

//如果是multipart/form-data就用MultiPartRequestWrapper進(jìn)行包裝

//MultiPartRequestWrapper

StrutsRequestWrapper的子類,兩者都是HttpServletRequest實(shí)現(xiàn)

//此時(shí)在MultiPartRequestWrapper中就會(huì)把Files給解析出來,用于文件上傳

//所有request都會(huì)StrutsRequestWrapper進(jìn)行包裝,StrutsRequestWrapper是可以訪問ValueStack

//下面是參見Dispatcher的wrapRequest

// String content_type = request.getContentType();

//if(content_type!= null&&content_type.indexOf(“multipart/form-data”)!=-1){

//MultiPartRequest multi =getContainer().getInstance(MultiPartRequest.class);

//request MultiPartRequestWrapper(multi,request,getSaveDir(servletContext));

//} else {

//

request = new StrutsRequestWrapper(request);

// }

request = prepareDispatcherAndWrapRequest(request, response);

ActionMapping mapping;

try {

//根據(jù)url取得對(duì)應(yīng)的Action的配置信息

//看一下注入的DefaultActionMapper的getMapping()方法.Action的配置信息存儲(chǔ)在 ActionMapping對(duì)象中

mapping

=

actionMapper.getMapping(request, dispatcher.getConfigurationManager());

} catch(Exception ex){

log.error(“error getting ActionMapping”, ex);

dispatcher.sendError(request,return;

}

//如果找不到對(duì)應(yīng)的action配置,則直接返回。比如你輸入***.jsp等等

//這兒有個(gè)例外,就是如果path是以“/struts”開頭,則到初始參數(shù)packages配置的包路徑去查找對(duì)應(yīng)的靜態(tài)資源并輸出到頁面流中,當(dāng)然.class文件除外。如果再?zèng)]有則跳轉(zhuǎn)到

response,servletContext, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, ex);

=new 404

if(mapping == null){

// there is no action in this request, should we look for a static resource?

String resourcePath = RequestUtils.getServletPath(request);

if(“".equals(resourcePath)&& null!= request.getPathInfo()){

resourcePath = request.getPathInfo();

}

if(staticResourceLoader.canHandle(resourcePath)){

// 在DefaultStaticContentLoader

:return

serveStatic

&&(resourcePath.startsWith(”/struts“)|| resourcePath.startsWith(”/static“));

staticResourceLoader.findStaticResource(resourcePath, response);

} else {

// this is a normal request, let it pass through

chain.doFilter(request, response);

}

// The framework did its job here

return;

}

//正式開始Action的方法

dispatcher.serviceAction(request, response, servletContext, mapping);

} finally {

try {

ActionContextCleanUp.cleanUp(req);

} finally {

UtilTimerStack.pop(timerKey);

}

}

}

public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)throws IOException, ServletException {

HttpServletRequest request =(HttpServletRequest)req;

request,HttpServletResponse response =(HttpServletResponse)res;

ServletContext servletContext = getServletContext();

String timerKey = ”FilterDispatcher_doFilter: “;

try {

// FIXME: this should be refactored better to not duplicate work with the action invocation

//先看看ValueStackFactory所注入的實(shí)現(xiàn)類OgnlValueStackFactory

//new OgnlValueStack

ValueStack

stack

= dispatcher.getContainer().getInstance(ValueStackFactory.class).createValueStack();

ActionContext ctx = new ActionContext(stack.getContext());

ActionContext.setContext(ctx);

UtilTimerStack.push(timerKey);

//如果是multipart/form-data就用MultiPartRequestWrapper進(jìn)行包裝

//MultiPartRequestWrapperHttpServletRequest實(shí)現(xiàn)

//此時(shí)在MultiPartRequestWrapper中就會(huì)把Files給解析出來,用于文件上傳

//所有request都會(huì)StrutsRequestWrapper進(jìn)行包裝,StrutsRequestWrapper是可以訪問ValueStack

//下面是參見Dispatcher的wrapRequest

// String content_type = request.getContentType();

//if(content_type!= null&&content_type.indexOf(”multipart/form-data“)!=-1){

//MultiPartRequest multi =getContainer().getInstance(MultiPartRequest.class);

//request MultiPartRequestWrapper(multi,request,getSaveDir(servletContext));

//} else {

//

request = new StrutsRequestWrapper(request);

// }

request = prepareDispatcherAndWrapRequest(request, response);

ActionMapping mapping;

try {

=new

StrutsRequestWrapper的子類,兩者都是

//根據(jù)url取得對(duì)應(yīng)的Action的配置信息

//看一下注入的DefaultActionMapper的getMapping()方法.Action的配置信息存儲(chǔ)在 ActionMapping對(duì)象中

mapping

} catch(Exception ex){

log.error(”error getting ActionMapping“, ex);

dispatcher.sendError(request,return;

}

//如果找不到對(duì)應(yīng)的action配置,則直接返回。比如你輸入***.jsp等等

//這兒有個(gè)例外,就是如果path是以“/struts”開頭,則到初始參數(shù)packages配置的包路徑去查找對(duì)應(yīng)的靜態(tài)資源并輸出到頁面流中,當(dāng)然.class文件除外。如果再?zèng)]有則跳轉(zhuǎn)到404

if(mapping == null){

// there is no action in this request, should we look for a static resource?

String resourcePath = RequestUtils.getServletPath(request);

if(”“.equals(resourcePath)&& null!= request.getPathInfo()){

resourcePath = request.getPathInfo();

}

if(staticResourceLoader.canHandle(resourcePath)){

// 在DefaultStaticContentLoader

:return

serveStatic

&&(resourcePath.startsWith(”/struts“)|| resourcePath.startsWith(”/static“));

staticResourceLoader.findStaticResource(resourcePath, response);

} else {

// this is a normal request, let it pass through

chain.doFilter(request, response);

}

// The framework did its job here

return;

}

request,response,servletContext, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, ex);

=

actionMapper.getMapping(request, dispatcher.getConfigurationManager());

//正式開始Action的方法

dispatcher.serviceAction(request, response, servletContext, mapping);

} finally {

try {

ActionContextCleanUp.cleanUp(req);

} finally {

UtilTimerStack.pop(timerKey);

}

}

}

//下面是ActionMapper接口的實(shí)現(xiàn)類 DefaultActionMapper的getMapping()方法的源代碼:

public ActionMapping getMapping(HttpServletRequest request,ConfigurationManager configManager){

ActionMapping mapping = new ActionMapping();

String uri = getUri(request);//得到請(qǐng)求路徑的URI,如:testAtcion.action或testAction.do

int indexOfSemicolon = uri.indexOf(”;“);//修正url的帶;jsessionid 時(shí)找不到而且的bug

uri =(indexOfSemicolon >-1)? uri.substring(0, indexOfSemicolon): uri;

uri = dropExtension(uri, mapping);//刪除擴(kuò)展名,默認(rèn)擴(kuò)展名為action

if(uri == null){

return null;

}

parseNameAndNamespace(uri, mapping, configManager);//匹配Action的name和namespace

handleSpecialParameters(request, mapping);//去掉重復(fù)參數(shù)

//如果Action的name沒有解析出來,直接返回

if(mapping.getName()== null){

returnnull;

}

//下面處理形如testAction!method格式的請(qǐng)求路徑

if(allowDynamicMethodCalls){

// handle ”name!method“ convention.String name = mapping.getName();

int exclamation = name.lastIndexOf(”!“);//!是Action名稱和方法名的分隔符

if(exclamation!=-1){

mapping.setName(name.substring(0, exclamation));//提取左邊為name

mapping.setMethod(name.substring(exclamation + 1));//提取右邊的method

}

}

return mapping;

}

//下面是ActionMapper接口的實(shí)現(xiàn)類 DefaultActionMapper的getMapping()方法的源代碼:

public ActionMapping getMapping(HttpServletRequest request,ConfigurationManager configManager){

ActionMapping mapping = new ActionMapping();

String uri = getUri(request);//得到請(qǐng)求路徑的URI,如:testAtcion.action或testAction.do

int indexOfSemicolon = uri.indexOf(”;“);//修正url的帶;jsessionid 時(shí)找不到而且的bug

uri =(indexOfSemicolon >-1)? uri.substring(0, indexOfSemicolon): uri;

uri = dropExtension(uri, mapping);//刪除擴(kuò)展名,默認(rèn)擴(kuò)展名為action

if(uri == null){

return null;

}

parseNameAndNamespace(uri, mapping, configManager);//匹配Action的name和namespace

handleSpecialParameters(request, mapping);//去掉重復(fù)參數(shù)

//如果Action的name沒有解析出來,直接返回

if(mapping.getName()== null){

returnnull;

}

//下面處理形如testAction!method格式的請(qǐng)求路徑

if(allowDynamicMethodCalls){

// handle ”name!method“ convention.String name = mapping.getName();

int exclamation = name.lastIndexOf(”!“);//!是Action名稱和方法名的分隔符

if(exclamation!=-1){

mapping.setName(name.substring(0, exclamation));//提取左邊為name

mapping.setMethod(name.substring(exclamation + 1));//提取右邊的method

}

}

return mapping;

}

從代碼中看出,getMapping()方法返回ActionMapping類型的對(duì)象,該對(duì)象包含三個(gè)參數(shù):Action的name、namespace和要調(diào)用的方法method。

如果getMapping()方法返回ActionMapping對(duì)象為null,則FilterDispatcher認(rèn)為用戶請(qǐng)求不是Action,自然另當(dāng)別論,F(xiàn)ilterDispatcher會(huì)做一件非常有意思的事:如果請(qǐng)求以/struts開頭,會(huì)自動(dòng)查找在web.xml文件中配置的 packages初始化參數(shù),就像下面這樣:

struts2

org.apache.struts2.dispatcher.FilterDispatcher

packages

com.lizanhong.action

struts2

org.apache.struts2.dispatcher.FilterDispatcher

packages

com.lizanhong.action

FilterDispatcher會(huì)將com.lizanhong.action包下的文件當(dāng)作靜態(tài)資源處理,即直接在頁面上顯示文件內(nèi)容,不過會(huì)忽略擴(kuò)展名為class的文件。比如在com.lizanhong.action包下有一個(gè)aaa.txt的文本文件,其內(nèi)容為“中華人民共和國”,訪問

http://localhost:8081/Struts2Demo/struts/aaa.txt時(shí)會(huì)輸出txt中的內(nèi)容

FilterDispatcher.findStaticResource()方法

protectedvoid findStaticResource(String

name,HttpServletRequest

request, HttpServletResponse response)throws IOException {

if(!name.endsWith(”.class“)){//忽略class文件

//遍歷packages參數(shù)

for(String pathPrefix : pathPrefixes){

InputStream is = findInputStream(name, pathPrefix);//讀取請(qǐng)求文件流

if(is!= null){

...// set the content-type header

String contentType = getContentType(name);//讀取內(nèi)容類型

if(contentType!= null){

response.setContentType(contentType);//重新設(shè)置內(nèi)容類型

}

...try {

//將讀取到的文件流以每次復(fù)制4096個(gè)字節(jié)的方式循環(huán)輸出

copy(is, response.getOutputStream());

} finally {

is.close();

}

return;

}

}

}

}

protectedvoid findStaticResource(String

name,HttpServletRequest

request, HttpServletResponse response)throws IOException {

if(!name.endsWith(”.class“)){//忽略class文件

//遍歷packages參數(shù)

for(String pathPrefix : pathPrefixes){

InputStream is = findInputStream(name, pathPrefix);//讀取請(qǐng)求文件流

if(is!= null){

...// set the content-type header

String contentType = getContentType(name);//讀取內(nèi)容類型

if(contentType!= null){

response.setContentType(contentType);//重新設(shè)置內(nèi)容類型

}

...try {

//將讀取到的文件流以每次復(fù)制4096個(gè)字節(jié)的方式循環(huán)輸出

copy(is, response.getOutputStream());

} finally {

is.close();

}

return;

}

}

}

}

如果用戶請(qǐng)求的資源不是以/struts開頭——可能是.jsp文件,也可能是.html文件,則通過過濾器鏈繼續(xù)往下傳送,直到到達(dá)請(qǐng)求的資源為止。

如果getMapping()方法返回有效的ActionMapping對(duì)象,則被認(rèn)為正在請(qǐng)求某個(gè)Action,將調(diào)用 Dispatcher.serviceAction(request, response, servletContext, mapping)方法,該方法是處理Action的關(guān)鍵所在。

下面就來看serviceAction,這又回到全局變量dispatcher中了

//Load Action class for mapping and invoke the appropriate Action method, or go directly to the Result.public void serviceAction(HttpServletRequest request, HttpServletResponse response, ServletContext context,ActionMapping mapping)throws ServletException {

//createContextMap方法主要把Application、Session、Request的key value值拷貝到Map中

Map extraContext = createContextMap(request, response, mapping, context);

// If there was a previous value stack, then create a new copy and pass it in to be used by the new Action

ValueStack

stack

=

(ValueStack)request.getAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY);

boolean nullStack = stack == null;

if(nullStack){

ActionContext ctx = ActionContext.getContext();

if(ctx!= null){

stack = ctx.getValueStack();

}

}

if(stack!= null){

extraContext.put(ActionContext.VALUE_STACK, valueStackFactory.createValueStack(stack));

}

String timerKey = ”Handling request from Dispatcher“;

try {

UtilTimerStack.push(timerKey);

String namespace = mapping.getNamespace();

String name = mapping.getName();

String method = mapping.getMethod();

Configuration config = configurationManager.getConfiguration();

//創(chuàng)建一個(gè)Action的代理對(duì)象,ActionProxyFactory是創(chuàng)建ActionProxy的工廠

//參考實(shí)現(xiàn)類:DefaultActionProxy和DefaultActionProxyFactory

ActionProxy

proxy

= config.getContainer().getInstance(ActionProxyFactory.class).createActionProxy(namespace, name, method, extraContext, true, false);

request.setAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY, proxy.getInvocation().getStack());

// if the ActionMapping says to go straight to a result, do it!

//如果是Result,則直接轉(zhuǎn)向,關(guān)于Result,ActionProxy,ActionInvocation下一講中再分析

if(mapping.getResult()!= null){

Result result = mapping.getResult();

result.execute(proxy.getInvocation());

} else {

//執(zhí)行Action

proxy.execute();

}

// If there was a previous value stack then set it back onto the request

if(!nullStack){

request.setAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY, stack);

}

} catch(ConfigurationException e){

// WW-2874 Only log error if in devMode

if(devMode){

LOG.error(”Could not find action or result“, e);

}

else {

LOG.warn(”Could not find action or result“, e);

}

sendError(request, HttpServletResponse.SC_NOT_FOUND, e);

} catch(Exception e){

sendError(request,} finally {

UtilTimerStack.pop(timerKey);

}

} 下面開始講一下主菜ActionProxy了.在這之前最好先去了解一下動(dòng)態(tài)Proxy的基本知識(shí).ActionProxy是Action的一個(gè)代理類,也就是說Action的調(diào)用是通過ActionProxy實(shí)現(xiàn)的,其實(shí)就是調(diào)用了ActionProxy.execute()方法,而該方法又調(diào)用了ActionInvocation.invoke()方法。歸根到底,最后調(diào)用的是DefaultActionInvocation.invokeAction()方法。DefaultActionInvocation()->init()->createAction()。

最后

調(diào)

用ActionProxy.exute()-->ActionInvocation.invoke()-->Intercepter.intercept()-->ActionInvocation.invokeActionOnly()-->invokeAction()這里的步驟是先由ActionProxyFactory創(chuàng)建ActionInvocation和ActionProxy.public ActionProxy createActionProxy(String namespace, String actionName, String methodName, Map extraContext, boolean executeResult, boolean cleanupContext){

ActionInvocation inv = new DefaultActionInvocation(extraContext, true);

container.inject(inv);

return }

public ActionProxy createActionProxy(String namespace, String actionName, String methodName, Map extraContext, boolean executeResult, boolean cleanupContext){

createActionProxy(inv,namespace,actionName,methodName, executeResult, cleanupContext);

response,context, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e);

response,context,ActionInvocation inv = new DefaultActionInvocation(extraContext, true);

container.inject(inv);

return }

下面先看DefaultActionInvocation的init方法

public void init(ActionProxy proxy){

this.proxy = proxy;

Map contextMap = createContextMap();

// Setting this so that other classes, like object factories, can use the ActionProxy and other

// contextual information to operate

ActionContext actionContext = ActionContext.getContext();

if(actionContext!= null){

actionContext.setActionInvocation(this);

}

//創(chuàng)建Action,struts2中每一個(gè)Request都會(huì)創(chuàng)建一個(gè)新的Action

createAction(contextMap);

if(pushAction){

stack.push(action);

contextMap.put(”action“, action);

}

invocationContext = new ActionContext(contextMap);

invocationContext.setName(proxy.getActionName());

// get a new List so we don't get problems with the iterator if someone changes the list

List

interceptorList

=

new ArrayList(proxy.getConfig().getInterceptors());

interceptors = interceptorList.iterator();

createActionProxy(inv,namespace,actionName,methodName, executeResult, cleanupContext);

}

protected void createAction(Map contextMap){

// load action

String timerKey = ”actionCreate: “ + proxy.getActionName();

try {

UtilTimerStack.push(timerKey);

//默認(rèn)為SpringObjectFactory:struts.objectFactory=spring.這里非常巧妙,在struts.properties中可以重寫這個(gè)屬性

//在前面BeanSelectionProvider中通過配置文件為ObjectFactory設(shè)置實(shí)現(xiàn)類

//這里以Spring為例,這里會(huì)調(diào)到SpringObjectFactory的buildBean方法,可以通過ApplicationContext的getBean()方法得到Spring的Bean

action

=

objectFactory.buildAction(proxy.getActionName(), proxy.getNamespace(), proxy.getConfig(), contextMap);

} catch(InstantiationException e){

throw new

XWorkException(”Unable

to

intantiate

Action!“,e, proxy.getConfig());

} catch(IllegalAccessException e){

throw new XWorkException(”Illegal access to constructor, is it public?", e, proxy.getConfig());

} catch(Exception e){

...} finally {

UtilTimerStack.pop(timerKey);

}

if(actionEventListener!= null){

action = actionEventListener.prepare(action, stack);

}

}

//SpringObjectFactory

public Object buildBean(String beanName, Map extraContext, boolean injectInternal)throws Exception {

Object o = null;

try {

//SpringObjectFactory

會(huì)

web.xml

中的

第五篇:簡易photoshop代碼數(shù)字圖像處理實(shí)驗(yàn)報(bào)告

一.一個(gè)簡單的“photoshop”軟件 二.設(shè)計(jì)目的:

數(shù)字圖像處理,就是用數(shù)字計(jì)算機(jī)及其他有關(guān)數(shù)字技術(shù),對(duì)圖像進(jìn)行處理,以達(dá)到預(yù)期的目的。隨著計(jì)算機(jī)的發(fā)展,圖像處理技術(shù)在許多領(lǐng)域得到了廣泛應(yīng)用,數(shù)字圖像處理已成為電子信息、通信、計(jì)算機(jī)、自動(dòng)化、信號(hào)處理等專業(yè)的重要課程。

數(shù)字圖像處理課程設(shè)計(jì)是在完成數(shù)字圖像處理的相關(guān)理論的學(xué)習(xí)后,進(jìn)行的綜合性訓(xùn)練課程,其目的主要包括:

1、使學(xué)生進(jìn)一步鞏固數(shù)字圖像處理的基本概念、理論、分析方法和實(shí)現(xiàn)方法;

2、增強(qiáng)學(xué)生應(yīng)用VC++編寫數(shù)字圖像處理的應(yīng)用程序及分析、解決實(shí)際問題的能力;

3、嘗試將所學(xué)的內(nèi)容解決實(shí)際工程問題,培養(yǎng)學(xué)生的工程實(shí)踐能力,提高工科學(xué)生的就業(yè)能力。

三.設(shè)計(jì)內(nèi)容: 1.打開圖像: 主要代碼:

static char szFilter[]=“BMP文件(*.bmp)|*.bmp||”;//定義過濾文件的類型

CString filename;

int ret=dlg.DoModal();//運(yùn)行打開文件對(duì)方框

if(ret==IDOK)

{

filename=dlg.GetFileName();

//獲取所選擇圖像的路徑

m_dib.LoadFromFile(filename);

//加載圖像

if(!m_dib.m_bLoaded)

//判斷是否加載圖像成功

{ AfxMessageBox(“圖像打不開”);

} return;

CFileDialog dlg(TRUE,“bmp”,NULL, OFN_HIDEREADONLY|OFN_OVERWRITEPROMPT,szFilter);//定義文件對(duì)話框?qū)?/p>

效果圖:

2.水平鏡像:把圖像的第一列和最后一列調(diào)轉(zhuǎn),第二列和倒數(shù)第二列換過來,以此類推下去,直到第nw/2為止。代碼: int temp,i,j;

for(j=0;j

for(i=0;i

{

temp=m_dib.m_pdata[j*nw+i];

m_dib.m_pdata[j*nw+i]=m_dib.m_pdata[nw-i-1+j*nw];

m_dib.m_pdata[nw-i-1+j*nw]=temp;

} 效果圖:

3.素描風(fēng)格:先把灰度值與右下的作對(duì)比,如果差值大于一個(gè)值則說明這是輪廓,先把非輪廓的位置像素置為黑色,最后對(duì)所有像素進(jìn)行底片化處理 代碼: int temp,i,j;

for(j=0;j

for(i=0;i

{

temp=m_dib.m_pdata[j*nw+i]-m_dib.m_pdata[(j+1)*nw+i+1];

} if(temp<10)m_dib.m_pdata[j*nw+i]=0;

//黑色為0

for(j=0;j

for(i=0;i

{

int gray=m_dib.m_pdata[j*nw+i];

m_dib.m_pdata[j*nw+i]=255-gray;

}

圖:

4圖像霧化:在圖像中引入一定的隨機(jī)值,打亂圖像中的像素值

代碼:

int i,j,k,dat;

//i表示列,j表行

byte *ptemp=(byte *)new byte[nw*nh];

memset(ptemp,0,nw*nh);

for(j=0;j

for(i=0;i

{

k=rand()%8;//取任意的隨機(jī)值

dat=j*nw+i+k;if(dat>=nw*nh)dat=nw*nh-1;ptemp[j*nw+i]=m_dib.m_pdata[dat];

} memcpy(m_dib.m_pdata,ptemp,nw*nh);效果圖:

5.浮雕處理:通過勾畫圖象輪廓和降低周圍像素色值,從而生成具有凹凸感的浮雕效果。其方法是生成一緩沖區(qū),計(jì)算當(dāng)前像素的左上角與右下角的像素值之差,再加上一個(gè)補(bǔ)值。將其存儲(chǔ)到緩沖區(qū)。再將緩沖區(qū)的數(shù)據(jù)逐點(diǎn)替換到圖像中并顯示出來。代碼:

int w=3,i,j;

//w為模板寬度

BYTE *p=new BYTE[nw*nh];

memcpy(p,m_dib.m_pdata,nw*nh);

for(j=w/2;j

for(i= w/2;i

{

p[j*nw+i]=m_dib.m_pdata[(j-1)*nw+i-1]*(1)+m_dib.m_pdata[(j+1)*nw+i+1]*(-1)+120;

}

memcpy(m_dib.m_pdata,p,nw*nh);

delete []p;效果圖:

6.直方圖均衡化 代碼:

int n[256]={0},g[256]={0};//定義頻數(shù)數(shù)組n,均衡化每個(gè)像素的灰度級(jí)的數(shù)組g

double f[256],t[256];//定義頻率數(shù)組f,累加的頻率數(shù)組t

int g_max=0,g_mim=255;

int i,j,k,z;

for(j=0;j

//統(tǒng)計(jì)灰度級(jí)的頻數(shù)n for(i=0;i

z=m_dib.m_pdata[j*nw+i];

n[z]++;

}

for(k=0;k<=255;k++)

//統(tǒng)計(jì)每個(gè)灰度級(jí)出現(xiàn)的頻率

f[k]=n[k]/(nw*nh*1.0);

//累計(jì)灰度級(jí)的頻率

t[0]=f[0];for(k=1;k<=255;k++)

t[k]=t[k-1]+f[k];

for(j=0;j

for(i=0;i

g_max=w>g_max?w:g_max;//得到最大值

g_mim=w

}

for(k=0;k<=255;k++)

//利用公式求每個(gè)像素均衡化后的灰度級(jí)

g[k]=(int)((g_max-g_mim)*t[k]+g_mim+0.5);

for(j=0;j

//逐個(gè)替換

for(i=0;i

k=m_dib.m_pdata[j*nw+i];

m_dib.m_pdata[j*nw+i]=g[k];

}

for(j=0;j

//計(jì)算均衡化的直方圖

{

//繪制原圖像的直方圖

for(i=0;i

{

BYTE temp=m_dib.m_pdata[j*nw+i];

m_hist[temp]++;} m_bHist=true;

CString str;int nh=m_dib.GetDIBHeight();int i;// 畫坐標(biāo)軸

// 繪制坐標(biāo)軸

pDC->MoveTo(410,nh+20);//(410,nh+20)是直方圖的左上角坐標(biāo)

// 垂直軸

pDC->LineTo(410,nh+200);//(410,nh+200)是直方圖的左下角坐標(biāo)

// 水平軸

pDC->LineTo(710,nh+200);//(710,nh+200)是直方圖的右下角坐標(biāo)

// 寫X軸刻度值

str.Format(“0”);pDC->TextOut(410, nh+200+10, str);str.Format(“50”);pDC->TextOut(460, nh+200+10, str);str.Format(“100”);pDC->TextOut(510, nh+200+10, str);str.Format(“150”);pDC->TextOut(560, nh+200+10, str);str.Format(“200”);pDC->TextOut(610, nh+200+10, str);str.Format(“255”);pDC->TextOut(665, nh+200+10, str);// 繪制X軸刻度 for(i = 0;i < 256;i += 25){

if((i & 1)== 0){

} // 10的倍數(shù)

pDC->MoveTo(i + 10, nh+200-2);pDC->LineTo(i + 10, nh+200+2);

}

else {

} // 10的倍數(shù)

pDC->MoveTo(i + 10, nh+200-2);pDC->LineTo(i + 10, nh+200+2);} // 繪制X軸箭頭

pDC->MoveTo(705,nh+200-5);pDC->LineTo(710,nh+200);pDC->LineTo(705,nh+200+5);// 繪制y軸箭頭

pDC->MoveTo(410,nh+20);pDC->LineTo(405,nh+20+5);pDC->MoveTo(410,nh+20);pDC->LineTo(415,nh+20+5);int max=0;for(i=0;i<256;i++)if(m_yuan[i]>max){

} max=m_yuan[i];

for(i=0;i<256;i++)pDC->MoveTo(410+i,nh+200);pDC->LineTo(410+i,nh+200-(m_yuan[i]*160/max));} if(m_bHist==true)//繪畫新的直方圖 {

CString str;int nh=m_dib.GetDIBHeight();int i;// 畫坐標(biāo)軸 // 繪制坐標(biāo)軸

pDC->MoveTo(10,nh+20);//(10,nh+20)是直方圖的左上角坐標(biāo)

// 垂直軸

pDC->LineTo(10,nh+200);//(10,nh+200)是直方圖的左下角坐標(biāo)

// 水平軸

pDC->LineTo(310,nh+200);//(310,nh+200)是直方圖的右下角坐標(biāo)

// 寫X軸刻度值 str.Format(“0”);

pDC->TextOut(10, nh+200+10, str);str.Format(“50”);pDC->TextOut(60, nh+200+10, str);str.Format(“100”);pDC->TextOut(110, nh+200+10, str);str.Format(“150”);pDC->TextOut(160, nh+200+10, str);str.Format(“200”);pDC->TextOut(210, nh+200+10, str);str.Format(“255”);pDC->TextOut(265, nh+200+10, str);// 繪制X軸刻度 for(i = 0;i < 256;i += 25){

if((i & 1)== 0){ // 10的倍數(shù)

} else {

// 10的倍數(shù)

pDC->MoveTo(i + 10, nh+200-2);pDC->LineTo(i + 10, nh+200+2);pDC->MoveTo(i + 10, nh+200-2);pDC->LineTo(i + 10, nh+200+2);} } // 繪制X軸箭頭

pDC->MoveTo(305,nh+200-5);pDC->LineTo(310,nh+200);pDC->LineTo(305,nh+200+5);// 繪制y軸箭頭 pDC->MoveTo(10,nh+20);pDC->LineTo(5,nh+20+5);pDC->MoveTo(10,nh+20);pDC->LineTo(15,nh+20+5);int max=0;for(i=0;i<256;i++)if(m_hist[i]>max){ max=m_hist[i];

for(i=0;i<256;i++)pDC->MoveTo(10+i,nh+200);pDC->LineTo(10+i,nh+200-(m_hist[i]*160/max));

} } 效果圖:

四.心得體會(huì):

通過這次數(shù)字圖像處理的課程設(shè)計(jì),對(duì)圖片有了更深一層的認(rèn)識(shí),理解了對(duì)圖像處理的一些原理,在這個(gè)課程設(shè)計(jì)過程中,需要自己去查閱資料,找資料,還需要理解所找到的資料,遇到問題獨(dú)立去思考,或者去請(qǐng)教同學(xué),給了我一個(gè)很好的鍛煉機(jī)會(huì),做事情一定要堅(jiān)持,最后一定會(huì)有收獲的。

五.參考文獻(xiàn):

《數(shù)字圖像處理》 ——電子工業(yè)出版社

《vc++數(shù)字圖像處理實(shí)驗(yàn)指導(dǎo)書》 曹老師、何家峰主編

下載詞法分析設(shè)計(jì)實(shí)驗(yàn)報(bào)告(附代碼)[精選合集]word格式文檔
下載詞法分析設(shè)計(jì)實(shí)驗(yàn)報(bào)告(附代碼)[精選合集].doc
將本文檔下載到自己電腦,方便修改和收藏,請(qǐng)勿使用迅雷等下載。
點(diǎn)此處下載文檔

文檔為doc格式


聲明:本文內(nèi)容由互聯(lián)網(wǎng)用戶自發(fā)貢獻(xiàn)自行上傳,本網(wǎng)站不擁有所有權(quán),未作人工編輯處理,也不承擔(dān)相關(guān)法律責(zé)任。如果您發(fā)現(xiàn)有涉嫌版權(quán)的內(nèi)容,歡迎發(fā)送郵件至:645879355@qq.com 進(jìn)行舉報(bào),并提供相關(guān)證據(jù),工作人員會(huì)在5個(gè)工作日內(nèi)聯(lián)系你,一經(jīng)查實(shí),本站將立刻刪除涉嫌侵權(quán)內(nèi)容。

相關(guān)范文推薦

    典型相關(guān)分析SAS代碼

    data fit; input X1 X2 X3 X4 X5 Y1 Y2 Y3; cards; 14651000 3446 98.8 2094.51 104.2 2555.14 2637.67 179.76 13985000 3339 113.8 2305.2233 133.8 2462.45 2670.99 161.......

    附1-實(shí)驗(yàn)報(bào)告書寫要求

    附1:實(shí)驗(yàn)報(bào)告書寫要求內(nèi)容要求:一、實(shí)驗(yàn)?zāi)康?直接復(fù)制實(shí)驗(yàn)指導(dǎo)中的實(shí)驗(yàn)?zāi)康摹?二、實(shí)驗(yàn)內(nèi)容 對(duì)于每個(gè)實(shí)驗(yàn)題,要求: (1) 抄題(不抄提示) (2) 應(yīng)用程序用戶界面截圖 (3) 控件主要屬性的設(shè)......

    東芝166維修代碼復(fù)印機(jī)故障(附故障手冊(cè))

    東芝166維修代碼復(fù)印機(jī)故障(附故障手冊(cè)) 東芝E-STUDIO 169 復(fù)印機(jī)故障(附故障手冊(cè)) 東芝169機(jī)器出現(xiàn)"請(qǐng)求維修",故障代碼C44 故障描述: 一、東芝169復(fù)印機(jī)出現(xiàn)"請(qǐng)求維修"符號(hào),故障......

    網(wǎng)上留言簿jsp實(shí)現(xiàn)(附所有代碼)

    計(jì)算機(jī)與信息學(xué)院 《計(jì)算機(jī)網(wǎng)絡(luò)系統(tǒng)實(shí)踐》報(bào)告 設(shè)計(jì)題目:網(wǎng)上留言簿的設(shè)計(jì)與實(shí)現(xiàn) 學(xué)生姓名: 學(xué)號(hào): 專業(yè)班級(jí):計(jì)算機(jī)科學(xué)與技術(shù)X班 2014年 1 月 二、選做部分 題目:網(wǎng)上留言簿的......

    醫(yī)療機(jī)構(gòu)基本情況調(diào)查表-附行政區(qū)劃代碼五篇

    附件3 醫(yī)療機(jī)構(gòu)基本情況調(diào)查表 機(jī)構(gòu)全稱: 組織機(jī)構(gòu)代碼:詳細(xì)地址: 機(jī)構(gòu)所在行政區(qū)縣代碼:機(jī)構(gòu)類別代碼機(jī)構(gòu)級(jí)別代碼:機(jī)構(gòu)等次代碼: 設(shè)置/主辦單位:分類管理代碼:政府辦衛(wèi)生機(jī)構(gòu)隸......

    熱分析實(shí)驗(yàn)報(bào)告

    熱分析實(shí)驗(yàn)報(bào)告 一、實(shí)驗(yàn)?zāi)康?1、了解STA449C綜合熱分析儀的原理及儀器裝置; 2、學(xué)習(xí)使用TG-DSC綜合熱分析方法。 二、實(shí)驗(yàn)內(nèi)容 1、對(duì)照儀器了解各步具體的操作及其目的。 2......

    擋土墻分析實(shí)驗(yàn)報(bào)告

    《工程力學(xué)A2》小組作業(yè)報(bào)告 擋土墻分析 院 系:土木建筑工程學(xué)院 組 名:第三組 組 長:侯森磊 成 員:侯森磊 符維濱 孫銘鍇 日 期:20151212 摘要:靈活運(yùn)用《理論力學(xué)》和《材料力......

    工作分析實(shí)驗(yàn)報(bào)告

    桂林電子科技大學(xué)信息科技學(xué)院 實(shí)驗(yàn)四 海 氏 三 要 素 在 工 作 評(píng) 價(jià) 中 的 運(yùn) 用 1554500103 楊虹 2017年5月 目錄 1.實(shí)驗(yàn)?zāi)康暮鸵?......................................

主站蜘蛛池模板: 亚洲a∨国产av综合av下载| 亚洲日韩乱码中文字幕| 少妇高潮惨叫喷水在线观看| 国产在线国偷精品免费看| 国产在线视频一区二区三区欧美图片| 国产午夜福利不卡在线观看| 狠狠色噜噜狠狠狠狠av不卡| 欧美人与物videos另类| 午夜精品久久久久久久99老熟妇| 久久婷婷五月综合成人d啪| 少妇仑乱a毛片无码| 51视频国产精品一区二区| 内射少妇一区27p| 色婷婷久久久swag精品| 99热久久精里都是精品6| 国产精品亚洲а∨天堂免下载| 欧美人与动牲交zooz男人| 狠狠躁天天躁无码中文字幕图| 婷婷综合缴情亚洲狠狠| 亚洲第一天堂无码专区| 亚洲www啪成人一区二区麻豆| 性欧美丰满熟妇xxxx性久久久| 激情综合色综合久久综合| 成人做爰高潮片免费视频| 在线观看国产精品乱码app| 久久久久久综合岛国免费观看| 国产男小鲜肉同志免费| 亚洲av无码成人专区片在线观看| 中文字幕久热精品视频在线| 免费吃奶摸下激烈视频| 亚洲小说春色综合另类| 99久久免费看少妇高潮a片| 亚洲暴爽av人人爽日日碰| 亚洲日产av中文字幕无码偷拍| 精品国精品国产自在久国产应用| 无码天堂亚洲国产av| 久久99精品久久久久久琪琪| 国产永久免费高清在线| 亚洲欧美综合在线中文| 在线aⅴ亚洲中文字幕| 亚洲精品一区中文字幕乱码|