Java進階第11課?框架之Struts2全解析通俗易懂-從零開始學Java

1狗准、什么是框架克锣?

框架就是一組程序的集合,本質(zhì)上是一組jar包的集合腔长,jar包中存有class文件或一些資源文件袭祟。框架的誕生是為了體能幫助程序員快速進行項目的開發(fā)捞附,提供一些輔助性的巾乳、便捷性的開發(fā)API,該API中已經(jīng)對現(xiàn)有的編程語言sdk及一些功能進行了封裝鸟召,程序員只需要遵循框架的一些約定胆绊,即可調(diào)用該API快速開發(fā)出符合業(yè)務需求的功能及程序。

2欧募、Java的三層結(jié)構(gòu)與框架

Java開發(fā)中的分層結(jié)構(gòu)為:

表現(xiàn)層压状,也叫action層/包,負責處理與界面交互的相關操作跟继,主要框架有Struts2种冬,Spring MVC;

業(yè)務層镣丑,也叫service層/包,負責復雜的業(yè)務邏輯計算和判斷娱两,主要框架有Spring(繼承了事務處理的功能)莺匠;

持久層,也叫dao層/包谷婆,負責將業(yè)務邏輯數(shù)據(jù)進行持久化存儲慨蛙,主要框架有Hibernate,MyBatis等纪挎;

我們一般將用于表現(xiàn)層的框架叫做MVC框架期贫。

3、MVC模型

MVC是一種程序設計的思想模型异袄。將整個程序的功能縱向拆分為數(shù)據(jù)模型Model通砍,視圖View,控制器Controller烤蜕》馑铮控制器是連接模型和視圖的橋梁,通過控制器來更新模型對應的數(shù)據(jù)讽营,并將模型的數(shù)據(jù)展示在視圖中虎忌。

4、Struts2的發(fā)展歷史

由于早期的程序開發(fā)是基于Servlet+JSP+JavaBean最原始的開發(fā)模式橱鹏,基本上是按部就班地開發(fā)膜蠢,效率比較低下。

后來Apache組織推出了基于MVC模式的輕量級Web應用框架Apache Struts1,該結(jié)構(gòu)將整個程序開發(fā)的代碼結(jié)構(gòu)進行了合理的劃分莉兰,提供了一些比較實用的功能挑围,如驗證,國際化等糖荒。一經(jīng)推出杉辙,迅速流行。

但是經(jīng)過開發(fā)者的實踐捶朵,發(fā)現(xiàn)Struts1存在一些問題蜘矢,比如線程不安全,靈活性低泉孩,ServletAPI耦合性高硼端,頁面間傳值復雜等。

后來又有一些新的框架寓搬,如SpringMVC和OpenSymphony的WebWork, 他們能夠避免Struts1中的一些缺點珍昨,從而比Struts1更能讓開發(fā)者接受。

當然作為MVC框架的發(fā)起者Apache組織也不甘落后,在WebWork框架的基礎之上借鑒了Struts1的優(yōu)點重新開發(fā)了一個新的Struts框架镣典,即Struts2框架兔毙,該框架是一個輕量級的Web應用框架,該框架不兼容Struts1框架兄春。

5澎剥、Struts2框架的核心功能介紹

6、Struts2框架的使用步驟

1)拷貝struts2下載包中/apps/struts2-blank/WEB-INF/lib目錄中的jar包到項目中的WEB-INF/lib目錄中赶舆,將這些jar包右鍵->add as Library即可哑姚。

struts運行必備jar包介紹:

struts2-core-2.3.4.jar, 核心類庫;

xwork-core-2.3.4.jar, Command模式框架芜茵,用于是一個容器叙量,用于創(chuàng)建和銷毀bean對象;

ognl-3.0.3.jar, 對象圖導航語言九串,用于讀寫對象的屬性绞佩;

freemarker-2.3.18.jar, 用于編寫UI標簽的模板;

commons-logging-1.1.x.jar, 用于支持Log4j 和JDK的日志記錄猪钮;

commons-fileupload-1.2.2.jar, 文件上傳組件品山;

commons-io-2.0.1.jar, io讀寫操作(如文件傳輸)依賴的jar包;

commons-lang-2.5.jar, 對java.lang包的增強烤低;

2)在web.xml中配置Struts2的前端控制器StrutsPreparedAndExecuteFilter:

struts2

struts2

/*

3)拷貝struts.xml文件到項目的資源文件目錄中肘交;

4)定義一個類HelloAction,提供一個public String execute(){}的方法(方法名可以修改)扑馁,在其中返回一個字符串酸些,用于對應邏輯視圖的名稱,如login檐蚜。注意定義Action實現(xiàn)類既可以使用POJO即普通的Java對象外,還可以實現(xiàn)

5)在struts.xml文件中對HelloAction類進行配置沿侈,以表示將其對象的創(chuàng)建和銷毀的管理交給Struts2的xwork容器去管理闯第。

/pages/user/login.jsp

6) 在web根目錄/pages/user/下創(chuàng)建一個login.jsp文件。里面可以寫一句話:請登錄缀拭。

7) 部署web項目到tomcat服務器上咳短,通過瀏覽器訪問HelloAction:

http://localhost:8080/webproject/pss/hello.action

圖片發(fā)自簡書App

7、Struts2的執(zhí)行流程

1)web.xml文件中配置了Struts2的核心過濾器StrutsPrepareAndExecuteFilter蛛淋,用于攔截所有的url請求咙好。

2)在web項目啟動的時候,會執(zhí)行StrutsPrepareAndExecuteFilter對象中的init(FilterConfig)方法褐荷,在該方法中將傳入的FilterConfig對象包裝為FilterHostConfig對象勾效,創(chuàng)建并調(diào)用InitOperations對象中的initDispatcher(HostConfig)方法,在該方法中將HostConfig對象中的ServletContext對象和初始化參數(shù)Map對象包裝成一個Dispatcher對象,保存在StrutsPrepareAndExecuteFilter對象中层宫,并根據(jù)Dispatcher對象分別創(chuàng)建PrepareOperations和ExecuteOperations對象杨伙。前者用來做一些初始化和清理操作,如createActionContext, cleanupRequest, cleanupDispatcher等方法萌腿;后者有executeAction方法限匣,該方法用于調(diào)用dispatcher對象的serviceAction方法,傳入HttpServletRequest, HttpServletResponse, 以及ActionMapping對象毁菱。

3)瀏覽器通過url發(fā)起對web項目資源的訪問米死。如http://localhost:8080/webproject/pss/hello

4)當Tomcat收到請求后,經(jīng)過一些包裝和處理后贮庞,會執(zhí)行StrutsPrepareAndExecuteFilter對象中的doFilter方法峦筒,在該方法中先判斷請求的url是否是已排除的url,如果是贸伐,則直接調(diào)用FilterChain對象的doFilter(req, resp)方法進行放行勘天;如果不是,則先調(diào)用PrepareOperations對象中的setEncodingAndLocale方法捉邢,該方法最終目的是使用指定編碼格式(默認utf-8)對request進行編碼(調(diào)用request.setCharacterEncoding(encoding)方法), 以及調(diào)用response.setLocale(Locale)方法脯丝。

然后調(diào)用PrepareOperations對象的createActionContext方法,在該方法中先通過ValueStackFactory創(chuàng)建ValueStack對象伏伐,調(diào)用該對象的getContext()方法拿到map成員變量宠进,然后調(diào)用dispatcher對象的createContextMap方法,將返回的Map對象中的key-value值存入ValueStack對象中藐翎。

然后通過ValueStack對象中的map創(chuàng)建ActionContext對象材蹬,并將該對象保存到ActionContext中的靜態(tài)變量中。

調(diào)用PrepareOperations對象的wrapRequest(HttpServletRequest)方法將HttpServletRequest封裝為StrutsRequestWrapper對象吝镣,即子類對象堤器。該對象中有一個boolean變量disableRequestAttributeValueStackLookup,用于在getAttribute(String)方法被調(diào)用時末贾,決定是否不從ValueStack中取值闸溃。默認是false,即允許從ValueStack中取值拱撵。

調(diào)用PrepareOperations對象的findActionMapping(request,response,forceLookup)方法辉川,從request對象中根據(jù)struts.actionMapping這個key拿到ActionMapping對象并返回。如果request中沒有該對象或者其為null拴测,則通過dispatcher.getContainer().getInstance(ActionMapper.class).getMapping(request, dispatcher.getConfigurationManager())來創(chuàng)建出ActionMapping對象乓旗。

如果當前request對應的ActionMapping為null,經(jīng)過ExecuteOperations對象execute.executeStaticResourceRequest(request, response)確認請求的是靜態(tài)資源對象(即非Action對象), 則直接調(diào)用FilterChain對象的doFilter(request,response) 對當前請求進行放行處理集索;

否則屿愚,調(diào)用ExecuteOperations對象的executeAction方法汇跨,在該方法中會先根據(jù)ActionMapping對象來決定是否要調(diào)用struts.xml中注冊的某個Action對象,如果是渺鹦,則創(chuàng)建對應的ActionProxy(代理對象)扰法,并將請求的處理交給ActionProxy對象,ActionProxy則創(chuàng)建一個ActionInvocation的實例毅厚,由ActionInvocation實例來實現(xiàn)對Action實例中指定的業(yè)務方法進行調(diào)用塞颁。但在調(diào)用Action對象的前后會涉及到攔截器棧或攔截器對象的調(diào)用吸耿。

當Action被調(diào)用完畢祠锣,ActionInvocation會根據(jù)struts.xml中的配置找到對應的返回結(jié)果result,可以是JSP或html或其他Action鏈等咽安。

注意:在整個struts框架中伴网,所有的對象都是由xwork容器負責創(chuàng)建和管理的。

8妆棒、Struts2的配置相關的文件及其加載順序(由先到后):

2)struts-default.xml 在struts2-core-?.jar包中澡腾,主要包含了框架依賴對象的配置和結(jié)果類型,以及攔截器等配置糕珊;

圖片發(fā)自簡書App

3)struts-plugin.xml 文件存在于struts-?-plugin-?.jar包中动分,主要用于配置struts的框架,由框架提供红选;

4)struts.xml 文件澜公,就是我們在struts2項目的source folder目錄中定義的文件±撸可以用來配置常量坟乾,package和Action,攔截器等蝶防;

5)struts.properties 文件甚侣,該文件可以由開發(fā)者創(chuàng)建并跟struts.xml文件放在同一個目錄中,可以用來覆蓋default.properties中的常量的定義间学;

6)web.xml文件渺绒,該文件是web項目中WEB-INF目錄下的重要配置文件。

注意:由于加載有先后順序菱鸥,所以后面文件配置中的常量會覆蓋前面加載的文件中同名的常量。

9. struts2中常見常量介紹:

用于指定默認編碼集躏鱼,用在request.setCharacterEncoding(String)方法中氮采,以及freemarker、velocity等染苛。

其中freemarker是模板引擎鹊漠,是一種基于模板允許其中key的值變動主到,將其生成輸出的文本如html格式的文本的工具)。

圖片發(fā)自簡書App

其中velocity是一個基于java的模板引擎, 允許僅使用簡單的模板語言(template language)來引用由java代碼定義的對象躯概。

指定請求資源的后綴名登钥,如.action, 以及沒有后綴名等。

設置瀏覽器是否緩存靜態(tài)內(nèi)容娶靡,默認為true牧牢。一般在生產(chǎn)環(huán)境下使用,而在開發(fā)階段為了測試姿锭,最好關閉塔鳍。

當struts的配置文件(xml格式)修改后,系統(tǒng)自動重新加載呻此,而不用重啟tomcat轮纫。默認為false。

struts.devMode = true

設置開發(fā)者模式焚鲜,該模式下修改struts.xml文件后不需要重啟服務器即可生效掌唾。

設置默認的視圖主題樣式,simple指定為簡化的主題樣式忿磅。

struts.enable.DynamicMethodInvocation = false

設置是否支持動態(tài)方法調(diào)用糯彬。為true時,就可以在struts.xml配置“*”的通配符贝乎,來調(diào)用action里的方法情连。

例如:

/pages/success.jsp

/pages/error.jsp

調(diào)用時就可以通過url來傳遞方法名,即動態(tài)方法調(diào)用览效。如:

http://localhost:8080/webproject/pss/login_mymethod

表示系統(tǒng)會調(diào)用com.abc.action.LoginAction類的對象中的mymethod方法却舀。該方法返回“success”時,跳轉(zhuǎn)到web根目錄下/pages/success.jsp文件锤灿;如果返回“error”時挽拔,跳轉(zhuǎn)到web根目錄/pages/error.jsp文件。

10但校、struts.xml文件的編寫規(guī)則

常量的定義:

如果要在里面定義常量螃诅,格式為:

包的定義:

如果要定義包,使用

節(jié)點來定義状囱。

其中name屬性為包名术裸,不同的包,name值應該不同亭枷。

extends屬性表示當前的包繼承自哪個包袭艺,一般都繼承自struts-default包。繼承了struts-default包叨粘,則表示當前包擁有了struts-default包所定義的資源猾编,如返回結(jié)果類型瘤睹,攔截器等。struts-default包是在struts-core-?.jar/struts-default.xml文件中定義答倡。

namespace屬性表示定義了一個命名空間轰传,一般以”/“開頭,如”/pss“瘪撇。命令空間和節(jié)點的name屬性組合成了所在包下面的action對象的訪問路徑获茬。如

則action資源的請求路徑為:http://服務器ip:tomcat端口號/項目的上下文路徑/包的namespace值/action的name值.action

abstract屬性用來將包定義為抽象的包,即只能用來被繼承设江,而里面沒有定義任何的節(jié)點锦茁,也就是沒有任何的action對象。

Action實現(xiàn)類的定義:

class屬性對應Action實現(xiàn)類的全限定名叉存,默認是ActionSupport類;

method屬性指定要調(diào)用Action的業(yè)務方法码俩;

節(jié)點定義在節(jié)點中或者中,用于配置業(yè)務方法執(zhí)行結(jié)果對應跳轉(zhuǎn)或重定向到的視圖路徑歼捏。

格式為:

name屬性用來定義邏輯視圖名稿存,對應于action中業(yè)務方法執(zhí)行后返回的字符串,缺省為"success";

type屬性用來指定跳轉(zhuǎn)的類型瞳秽,缺省是dispatcher表示請求轉(zhuǎn)發(fā)到jsp文件(頁面)瓣履,redirect表示重定向到jsp文件,chain表示從一個action請求轉(zhuǎn)發(fā)到另一個action练俐,redirectAction表示從一個action重定向到另一個action袖迎,stream表示返回流對象,用于文件下載腺晾;

如:/pages/ok.jsp

注意:如果要訪問不同命名空間下的action燕锥,例如要訪問”/pss“命名空間中的name值為hello的action,則在節(jié)點中悯蝉,添加如下兩個節(jié)點:

/pss

hello

action的擴展:比如要執(zhí)行name值為hello的action對象中的abc()業(yè)務方法归形,有三種做法:

1)直接在節(jié)點中配置method屬性的值為abc;

2)http://服務器ip:端口號/web項目上下文路徑/package namespace/hello!abc

此種方式需要配置常量:

3)使用通配符

則請求的url為:http://服務器ip:端口號/web項目上下文路徑/package namespace/hello_abc

11鼻由、如何在Action中獲取request暇榴,response,session蕉世,cookie等蔼紧?

首先我們要明白在Servlet中的業(yè)務方法service方法中,已經(jīng)通過參數(shù)將HttpServletRequest和HttpServletResponse兩個對象傳入進來了狠轻,我們可以直接用奸例,通過request.getSession()就可以拿到Session對象,通過request.getCookies()就可以拿到所有的Cookie對象哈误。

那么我們現(xiàn)在來看下哩至,在Struts的Action中如何獲取上述四個對象呢?有兩種方式:

方式一:(有耦合,不推薦)通過實現(xiàn)Struts提供的感知接口來自動獲取蜜自,如ServletRequestAware菩貌,ServletResponseAware,SessionAware等接口重荠。

圖片發(fā)自簡書App

之所以能通過感知接口拿到相關的Servlet對象卫枝,是因為在struts-core-?.jar包中的struts-default.xml文件中定義了servletConfig對應的類憾筏。

圖片發(fā)自簡書App

我們來看看ServletConfigInterceptor類的代碼:

圖片發(fā)自簡書App

方式二:直接通過ServletActionContext工具類中的靜態(tài)方法來獲取相關對象。

圖片發(fā)自簡書App

方式三:(強烈推薦)通過ActionContext對象中的方法來獲取。ActionContext對象本身代表著當前Action對象的上下文環(huán)境信息透典,也就是對應著一次請求的相關信息。

圖片發(fā)自簡書App

ActionContext.getContext() 獲取到ActionContext的對象泻骤,通過該對象調(diào)用getParameters()獲取到所有參數(shù)的Map集合围肥。

ActionContext是線程安全的,里面定義了ThreadLocal actionContext對象婆芦,實現(xiàn)了將ActionContext對象與當前線程綁定在一起怕磨。

12、JSP頁面與Action組件間相互注入數(shù)據(jù)的幾種方式:

首先我們要明白消约,凡是請求中的參數(shù)肠鲫,可以在Action中直接使用request.getParameter(key)或者request.getParamterValues(key)方式來獲取到參數(shù)的值或數(shù)組值。但是這種做法很麻煩或粮,而且需要在Servlet中做類型轉(zhuǎn)換导饲。有沒有更好的做法呢?當然是有氯材,請看下文渣锦。

方式一:將Action看做一個Model對象,在Action中直接定義private的屬性名浓体,提供對應的setter方法即可泡挺。

方式二:(推薦的方式)創(chuàng)建一個含有屬性的Model類,在Action中通過對該Model類提供屬性及getter和setter方法命浴,頁面會通過ognl表達式對數(shù)據(jù)進行注入娄猫。

圖片發(fā)自簡書App

方式三:創(chuàng)建一個含有屬性的Model類,讓Action實現(xiàn)ModelDriven接口生闲,該接口的的泛型類型為該Model類媳溺。在Action中創(chuàng)建一個Model類的對象作為屬性,在復寫的getModel()方法中碍讯,返回當前Action中的Model類的對象悬蔽。

圖片發(fā)自簡書App

顯然方式一如果傳遞的數(shù)據(jù)個數(shù)比較多時,代碼比較臃腫捉兴;方式三需要實現(xiàn)ModelDriven接口蝎困,有耦合性录语;方式二顯然是最佳的使用方式。但在實際的開發(fā)中禾乘,經(jīng)常是方式二和方式一的組合使用澎埠。

13、攔截器Interceptor

所謂的攔截器是指能夠?qū)χ付ˋction對象的調(diào)用進行動態(tài)攔截的組件始藕,可以在調(diào)用之前和之后實施攔截并執(zhí)行某段代碼蒲稳,也可以完全阻止某個Action對象方法的調(diào)用。

攔截器主要的功能是將Action中的一些通用的功能提取出來伍派,定義在攔截器中江耀。當某個Action需要該功能時,只需要給該Action指定對應的攔截器即可诉植。從而提高了代碼的可重用性祥国,也實現(xiàn)類裝配式和可插拔式的體系結(jié)構(gòu),使得整個系統(tǒng)結(jié)構(gòu)更加靈活倍踪。

攔截器的特點:1系宫、簡化Action的實現(xiàn),將重復的單一功能從Action中剝離出來建车;2扩借、每個攔截器只實現(xiàn)某一種特定的功能;3缤至、攔截器的出現(xiàn)實現(xiàn)了代碼的模塊化編程(可插拔式編程)潮罪;4、攔截器整合了Actoin中重復的代碼(功能)领斥,提高了代碼的復用性嫉到。

攔截器棧Interceptor Stack,是將多個攔截器按照一定的順序連接形成的一條鏈月洛。當給某個Action對象指定了攔截器棧何恶,則在該Action對象方法被調(diào)用時,會按照攔截器棧中的先后順序來指定攔截的攔截方法嚼黔。

struts內(nèi)置的攔截器都定義在struts-core-?.jar包中的struts-default.xml文件中:

圖片發(fā)自簡書App

params攔截器细层,用于把請求參數(shù)設置到相應的Action對象的屬性中,并自動進行類型轉(zhuǎn)換唬涧;

modelDriven攔截器疫赎,用于將getModel()方法返回的模型對象存入到OgnlValueStack中。一般只需要讓Action實現(xiàn)ModelDriven接口碎节,即可使得Action配置了該攔截器捧搞;

exception攔截器,用在拋異常的時候,用于捕獲異常胎撇;

validation攔截器介粘,用于讀取項目中的*-validation.xml文件,并使得這些文件中聲明的校驗生效晚树;

token攔截器碗短,用于核對當前Action請求是否有效,防止重復提交Action請求题涨;

fileUpload攔截器,用于處理文件上傳总滩;

workflow攔截器纲堵,用于校驗,調(diào)用Action的validate方法闰渔,如果有錯誤席函,則重新定位到名為“input”的結(jié)果視圖;

servletConfig攔截器冈涧,用于通過感知接口茂附,獲取感應的對象,如HttpServletRequest, HttpServletResponse,HttpSession等督弓;

14营曼、自定義一個攔截器

開發(fā)步驟:

圖片發(fā)自簡書App

2)定義一個Action,如HelloAction愚隧,實現(xiàn)了ActionSupport接口蒂阱。

在struts.xml文件中配置如下,注意由于攔截器返回了login狂塘,所以也要配置录煤。當然我們可以直接把login這個result配置到中,但是這樣的話荞胡,每個用到該攔截器的action都要配置login妈踊。顯然,我們應該將login配置為一個全局的result泪漂。

3)接下來就是對攔截器的配置廊营,攔截器的配置其實也是在struts.xml文件中配置的:

首先要通過節(jié)點來定義攔截器,即指定對應的類和名字:

在上圖中窖梁,我們可以在節(jié)點中定義一個攔截器棧赘风,在該棧中將默認的攔截器棧與我們所定義的攔截器組合成一個新的攔截器棧。注意順序纵刘,先是defaultStack邀窃,然后才是我們定義的攔截器。如上圖。

然后通過節(jié)點來指定該包下面的action都同一應用的攔截器瞬捕。如:

注意:如果要對某一個action不使用我們自定義的攔截器棧鞍历,則需要在節(jié)點中聲明使用默認的攔截器棧。即:

15肪虎、國際化i18n

所謂的國際化劣砍,指的是讓程序能夠支持在不同的語言環(huán)境下顯示不同語言的內(nèi)容。如在中文環(huán)境下顯示中文內(nèi)容扇救,在英文語言環(huán)境下顯示英文內(nèi)容刑枝。

struts2支持國際化,是由于其內(nèi)置有i18n的攔截器:

那么如何才能在項目中配置國際化的語言內(nèi)容呢迅腔?

圖片發(fā)自簡書App

首先分別定義不同語言環(huán)境對應的properties文件装畅,如文件名為constant,則中文環(huán)境下的properties文件全名應該為constant_zh_CN.properties沧烈,英文環(huán)境下的properties文件的全名為constant_en_US.properties掠兄。

然后在struts中配置國際化文件:

最后在jsp文件下要用的話,必須使用taglib命令引入struts標簽庫:

在需要從properties文件中拿常量的地方锌雀,使用即可拿到key對應的值蚂夕。

注意:對于properties文件中key的值,如果要在action中拿到腋逆,需要action對象實現(xiàn)了ActionSupport接口婿牍,通過getText(key)即可拿到key在不同語言環(huán)境中的value值。

16惩歉、OGNL是什么牍汹?

Object Graphic Navigation Language對象圖導航語言,是一種表達式語言柬泽,可以理解為OGNL是EL表達式語言的一種升級版慎菲,通過簡單一致的表達式語法,可以存取對象的任意屬性锨并,調(diào)用對象的方法露该,遍歷整個對象的結(jié)構(gòu)圖,實現(xiàn)字段類型轉(zhuǎn)化等功能第煮。使用相同的表達式去存取對象的屬性解幼,取得對象中的數(shù)據(jù)。

該表達式是將對象的引用值用點串聯(lián)起來包警,從左到右撵摆,每一次表達式計算返回的結(jié)果成為當前對象,后面部分接著在當前對象上進行計算害晦,一直到全部表達式計算完成特铝,返回最后得到的對象。OGNL則針對這條基本原則進行不斷的擴充,從而使之支持對象樹鲫剿、數(shù)組鳄逾、容器的訪問,甚至是類似SQL中的投影選擇等操作灵莲。

例如雕凹,假設當前環(huán)境(對象)中的根對象是student,而student對象中有個scores數(shù)組政冻,該數(shù)組中第一個值為總分枚抵,則可以通過ognl表達式:studet.scores[0]拿到總分的值。

OGNL支持+-*/運算符明场,是struts2默認的表達式語言俄精;支持類的靜態(tài)方法的調(diào)用和值的訪問;支持賦值操作和表達式串聯(lián)榕堰;可以操作集合對象;可以直接new一個對象嫌套;

OGNL通常要結(jié)合Struts2的一些標志一起使用逆屡,如#,$,%;

其中#主要用來訪問ONGL上下文和action上下文踱讨,#代表ActionContext.getContext()魏蔗。

如#parameters.id[0]相當于request.getParameterValues("id").get(0);

#request.userName相當于request.getAttribute("userName");

#session.userName相當于session.getAttribute("userName");

#application.userName相當于application.getAttribute("userName");

attr 用于按request > session > application順序訪問其屬性(attribute) #attr.userName相當于按順序在以上三個范圍(scope)內(nèi)讀取userName屬性,直到找到為止;

構(gòu)造Map痹筛,如#{'foo1':'bar1', 'foo2':'bar2'};

17莺治、ValueStack值棧

本質(zhì)上是Struts2的接口com.opensymphony.xwork2.util.ValueStack,Struts容器使用com.opensymphony.xwork2.ognl.OgnlValueStack來封裝每一次請求的數(shù)據(jù)帚稠,也就是說每一次請求都會創(chuàng)建一個新的ValueStack對象谣旁,在該對象中封裝了本次請求的相關數(shù)據(jù)信息。也意味著Struts2中的ValueStack對象可以使用ognl表達式來存取其中的數(shù)據(jù)滋早。那么ValueStack對象可以通過request.getAttribute("struts.valueStack")的方式拿到榄审,也可以通過調(diào)用ActionContext對象的getValueStack()方法來拿到。也就是意味著在request對象中有一個名為struts.valueStack的key杆麸,其對應的值為ValueStack對象搁进。

我們先看看源碼:

圖片發(fā)自簡書App

其實OgnlValueStack對象的棧結(jié)構(gòu)的實現(xiàn),是由其里面的root變量來實現(xiàn)的昔头。

圖片發(fā)自簡書App

我們可以在root中拿到當前Action的對象饼问,在context中拿到作用域?qū)ο?request,session,application)的Map格式的對象及參數(shù)對象parameters等。

如果要獲取Action對象中的屬性的值揭斧,由于Action對象本身在root的棧頂位置莱革,所以在jsp中可以通過來直接獲取;

注意:

1) 有一種情況會導致Action不在棧頂位置驮吱,例如當前Action中new了一個對象作為其屬性的值茧妒。此時,可以在context的key為params中拿到值左冬。

2) 如果需要從root棧的棧頂拿值桐筏,則可以通過如下方式在jsp中拿到:

如果要獲取的值對應的key在ValueStack的context中,則在jsp中可以通過的方式獲取拇砰。

把數(shù)據(jù)放入ValueStack的root中:valueStack.getRoot().push(Object) 梅忌,valueStack.getRoot().add(0,Object),valueStack.set(key, Object)除破,以及在Action中帶有getter方法的屬性牧氮。

把數(shù)據(jù)放入ValueStack的context中,valueStack.getContext().put(key, value)或者ActionContext.getContext().put(key, value)瑰枫。

注意:在jsp中如果需要查看valueStack中的所有數(shù)據(jù)踱葛,則可以添加如下代碼:

18、輸入校驗

輸入校驗光坝,一般用于對jsp頁面在提交(發(fā)出請求)時尸诽,在被請求的Action中執(zhí)行validate()方法,開發(fā)者只需要在該方法中編寫驗證代碼即可盯另。如果驗證不通過性含,只需要調(diào)用super.addFileError("字段名稱","錯誤信息")即可在Action中業(yè)務方法被調(diào)用之前終止當前的請求。同時鸳惯,需要在struts.xml文件中配置名為input的result商蕴,用來指定當輸入校驗失敗時,需要跳轉(zhuǎn)到的頁面芝发。

如果某些業(yè)務方法不需要被校驗绪商,則可以通過在該方法上添加注解@SkipValidation即可。

圖片發(fā)自簡書App

如果只對Action中的業(yè)務方法abc()進行調(diào)用前的校驗辅鲸,則validate()方法的方法名改為validateAbc()即可部宿。

如果需要在某個方法被校驗失敗時跳轉(zhuǎn)到的不是input視圖,而是其它視圖瓢湃,比如abc視圖理张。則可以在被校驗的方法上通過注解來更改校驗失敗的視圖名。如@InputConfig(resultName="abc")绵患。

注意:

validation攔截器已經(jīng)對input方法作了特殊處理雾叭,不會對其進行校驗處理。

validation攔截器只是在調(diào)用input方法時執(zhí)行了validate或validateXxx方法落蝙,當校驗失敗時织狐,由該validate方法提供調(diào)用addFiledError()方法暂幼。在validation攔截器之后有個workflow攔截器,該攔截器會檢查FiledError中是否有錯誤數(shù)據(jù)移迫,如果有旺嬉,就會跳轉(zhuǎn)到input結(jié)果碼對應的頁面。

19厨埋、文件上傳

使用struts2提供的文件上傳組件相對來說比較容易些邪媳。

首先,在jsp頁面中荡陷,引入struts2的標簽庫struts-tag雨效,然后在需要上傳文件的地方使用標簽來讓用戶選擇文件:

圖片發(fā)自簡書App

在提交到的Action中,定義三個屬性废赞,并提供對應的setter方法徽龟,然后在業(yè)務方法如execute中進行文件的copy操作即可。然后在struts.xml文件中注冊此Action唉地。

注意:文件上傳要求jsp中form的請求時post据悔,且enctype="multipart/form-data"值。struts2的form標簽的method屬性的默認值就是post耘沼。

我們還可以通過參數(shù)注入的方式來設置FileUploadInterceptor攔截器的允許上傳文件最大值和允許上傳文件類型這兩個參數(shù)极颓。

圖片發(fā)自簡書App

具體設置如下:

1024*1024*5

png,jpg

20、文件下載

圖片發(fā)自簡書App
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末耕拷,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子托享,更是在濱河造成了極大的恐慌骚烧,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,194評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件闰围,死亡現(xiàn)場離奇詭異赃绊,居然都是意外死亡,警方通過查閱死者的電腦和手機羡榴,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,058評論 2 385
  • 文/潘曉璐 我一進店門碧查,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人校仑,你說我怎么就攤上這事忠售。” “怎么了迄沫?”我有些...
    開封第一講書人閱讀 156,780評論 0 346
  • 文/不壞的土叔 我叫張陵稻扬,是天一觀的道長。 經(jīng)常有香客問我羊瘩,道長泰佳,這世上最難降的妖魔是什么盼砍? 我笑而不...
    開封第一講書人閱讀 56,388評論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮逝她,結(jié)果婚禮上浇坐,老公的妹妹穿的比我還像新娘。我一直安慰自己黔宛,他們只是感情好近刘,可當我...
    茶點故事閱讀 65,430評論 5 384
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著宁昭,像睡著了一般跌宛。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上积仗,一...
    開封第一講書人閱讀 49,764評論 1 290
  • 那天疆拘,我揣著相機與錄音,去河邊找鬼寂曹。 笑死哎迄,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的隆圆。 我是一名探鬼主播漱挚,決...
    沈念sama閱讀 38,907評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼渺氧!你這毒婦竟也來了旨涝?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,679評論 0 266
  • 序言:老撾萬榮一對情侶失蹤侣背,失蹤者是張志新(化名)和其女友劉穎白华,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體贩耐,經(jīng)...
    沈念sama閱讀 44,122評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡弧腥,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,459評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了潮太。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片管搪。...
    茶點故事閱讀 38,605評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖铡买,靈堂內(nèi)的尸體忽然破棺而出更鲁,到底是詐尸還是另有隱情,我是刑警寧澤奇钞,帶...
    沈念sama閱讀 34,270評論 4 329
  • 正文 年R本政府宣布岁经,位于F島的核電站,受9級特大地震影響蛇券,放射性物質(zhì)發(fā)生泄漏缀壤。R本人自食惡果不足惜樊拓,卻給世界環(huán)境...
    茶點故事閱讀 39,867評論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望塘慕。 院中可真熱鬧筋夏,春花似錦、人聲如沸图呢。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,734評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽蛤织。三九已至赴叹,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間指蚜,已是汗流浹背乞巧。 一陣腳步聲響...
    開封第一講書人閱讀 31,961評論 1 265
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留摊鸡,地道東北人绽媒。 一個月前我還...
    沈念sama閱讀 46,297評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像免猾,于是被迫代替她去往敵國和親是辕。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 43,472評論 2 348

推薦閱讀更多精彩內(nèi)容