1、什么是框架?
框架就是一組程序的集合,本質(zhì)上是一組jar包的集合,jar包中存有class文件或一些資源文件。框架的誕生是為了體能幫助程序員快速進(jìn)行項(xiàng)目的開發(fā),提供一些輔助性的、便捷性的開發(fā)API,該API中已經(jīng)對(duì)現(xiàn)有的編程語(yǔ)言sdk及一些功能進(jìn)行了封裝,程序員只需要遵循框架的一些約定,即可調(diào)用該API快速開發(fā)出符合業(yè)務(wù)需求的功能及程序。
2、Java的三層結(jié)構(gòu)與框架
Java開發(fā)中的分層結(jié)構(gòu)為:
表現(xiàn)層,也叫action層/包,負(fù)責(zé)處理與界面交互的相關(guān)操作,主要框架有Struts2,Spring MVC;
業(yè)務(wù)層,也叫service層/包,負(fù)責(zé)復(fù)雜的業(yè)務(wù)邏輯計(jì)算和判斷,主要框架有Spring(繼承了事務(wù)處理的功能);
持久層,也叫dao層/包,負(fù)責(zé)將業(yè)務(wù)邏輯數(shù)據(jù)進(jìn)行持久化存儲(chǔ),主要框架有Hibernate,MyBatis等;
我們一般將用于表現(xiàn)層的框架叫做MVC框架。
3、MVC模型
MVC是一種程序設(shè)計(jì)的思想模型。將整個(gè)程序的功能縱向拆分為數(shù)據(jù)模型Model,視圖View,控制器Controller??刂破魇沁B接模型和視圖的橋梁,通過(guò)控制器來(lái)更新模型對(duì)應(yīng)的數(shù)據(jù),并將模型的數(shù)據(jù)展示在視圖中。
4、Struts2的發(fā)展歷史
由于早期的程序開發(fā)是基于Servlet+JSP+JavaBean最原始的開發(fā)模式,基本上是按部就班地開發(fā),效率比較低下。
后來(lái)Apache組織推出了基于MVC模式的輕量級(jí)Web應(yīng)用框架Apache Struts1,該結(jié)構(gòu)將整個(gè)程序開發(fā)的代碼結(jié)構(gòu)進(jìn)行了合理的劃分,提供了一些比較實(shí)用的功能,如驗(yàn)證,國(guó)際化等。一經(jīng)推出,迅速流行。
但是經(jīng)過(guò)開發(fā)者的實(shí)踐,發(fā)現(xiàn)Struts1存在一些問(wèn)題,比如線程不安全,靈活性低,ServletAPI耦合性高,頁(yè)面間傳值復(fù)雜等。
后來(lái)又有一些新的框架,如SpringMVC和OpenSymphony的WebWork, 他們能夠避免Struts1中的一些缺點(diǎn),從而比Struts1更能讓開發(fā)者接受。
當(dāng)然作為MVC框架的發(fā)起者Apache組織也不甘落后,在WebWork框架的基礎(chǔ)之上借鑒了Struts1的優(yōu)點(diǎn)重新開發(fā)了一個(gè)新的Struts框架,即Struts2框架,該框架是一個(gè)輕量級(jí)的Web應(yīng)用框架,該框架不兼容Struts1框架。
5、Struts2框架的核心功能介紹
6、Struts2框架的使用步驟
1)拷貝struts2下載包中/apps/struts2-blank/WEB-INF/lib目錄中的jar包到項(xiàng)目中的WEB-INF/lib目錄中,將這些jar包右鍵->add as Library即可。
struts運(yùn)行必備jar包介紹:
struts2-core-2.3.4.jar, 核心類庫(kù);
xwork-core-2.3.4.jar, Command模式框架,用于是一個(gè)容器,用于創(chuàng)建和銷毀bean對(duì)象;
ognl-3.0.3.jar, 對(duì)象圖導(dǎo)航語(yǔ)言,用于讀寫對(duì)象的屬性;
freemarker-2.3.18.jar, 用于編寫UI標(biāo)簽的模板;
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, 對(duì)java.lang包的增強(qiáng);
2)在web.xml中配置Struts2的前端控制器StrutsPreparedAndExecuteFilter:
struts2
struts2
/*
3)拷貝struts.xml文件到項(xiàng)目的資源文件目錄中;
4)定義一個(gè)類HelloAction,提供一個(gè)public String execute(){}的方法(方法名可以修改),在其中返回一個(gè)字符串,用于對(duì)應(yīng)邏輯視圖的名稱,如login。注意定義Action實(shí)現(xiàn)類既可以使用POJO即普通的Java對(duì)象外,還可以實(shí)現(xiàn)
5)在struts.xml文件中對(duì)HelloAction類進(jìn)行配置,以表示將其對(duì)象的創(chuàng)建和銷毀的管理交給Struts2的xwork容器去管理。
/pages/user/login.jsp
6) 在web根目錄/pages/user/下創(chuàng)建一個(gè)login.jsp文件。里面可以寫一句話:請(qǐng)登錄。
7) 部署web項(xiàng)目到tomcat服務(wù)器上,通過(guò)瀏覽器訪問(wèn)HelloAction:
http://localhost:8080/webproject/pss/hello.action

7、Struts2的執(zhí)行流程
1)web.xml文件中配置了Struts2的核心過(guò)濾器StrutsPrepareAndExecuteFilter,用于攔截所有的url請(qǐng)求。
2)在web項(xiàng)目啟動(dòng)的時(shí)候,會(huì)執(zhí)行StrutsPrepareAndExecuteFilter對(duì)象中的init(FilterConfig)方法,在該方法中將傳入的FilterConfig對(duì)象包裝為FilterHostConfig對(duì)象,創(chuàng)建并調(diào)用InitOperations對(duì)象中的initDispatcher(HostConfig)方法,在該方法中將HostConfig對(duì)象中的ServletContext對(duì)象和初始化參數(shù)Map對(duì)象包裝成一個(gè)Dispatcher對(duì)象,保存在StrutsPrepareAndExecuteFilter對(duì)象中,并根據(jù)Dispatcher對(duì)象分別創(chuàng)建PrepareOperations和ExecuteOperations對(duì)象。前者用來(lái)做一些初始化和清理操作,如createActionContext, cleanupRequest, cleanupDispatcher等方法;后者有executeAction方法,該方法用于調(diào)用dispatcher對(duì)象的serviceAction方法,傳入HttpServletRequest, HttpServletResponse, 以及ActionMapping對(duì)象。
3)瀏覽器通過(guò)url發(fā)起對(duì)web項(xiàng)目資源的訪問(wèn)。如http://localhost:8080/webproject/pss/hello
4)當(dāng)Tomcat收到請(qǐng)求后,經(jīng)過(guò)一些包裝和處理后,會(huì)執(zhí)行StrutsPrepareAndExecuteFilter對(duì)象中的doFilter方法,在該方法中先判斷請(qǐng)求的url是否是已排除的url,如果是,則直接調(diào)用FilterChain對(duì)象的doFilter(req, resp)方法進(jìn)行放行;如果不是,則先調(diào)用PrepareOperations對(duì)象中的setEncodingAndLocale方法,該方法最終目的是使用指定編碼格式(默認(rèn)utf-8)對(duì)request進(jìn)行編碼(調(diào)用request.setCharacterEncoding(encoding)方法), 以及調(diào)用response.setLocale(Locale)方法。
然后調(diào)用PrepareOperations對(duì)象的createActionContext方法,在該方法中先通過(guò)ValueStackFactory創(chuàng)建ValueStack對(duì)象,調(diào)用該對(duì)象的getContext()方法拿到map成員變量,然后調(diào)用dispatcher對(duì)象的createContextMap方法,將返回的Map對(duì)象中的key-value值存入ValueStack對(duì)象中。
然后通過(guò)ValueStack對(duì)象中的map創(chuàng)建ActionContext對(duì)象,并將該對(duì)象保存到ActionContext中的靜態(tài)變量中。
調(diào)用PrepareOperations對(duì)象的wrapRequest(HttpServletRequest)方法將HttpServletRequest封裝為StrutsRequestWrapper對(duì)象,即子類對(duì)象。該對(duì)象中有一個(gè)boolean變量disableRequestAttributeValueStackLookup,用于在getAttribute(String)方法被調(diào)用時(shí),決定是否不從ValueStack中取值。默認(rèn)是false,即允許從ValueStack中取值。
調(diào)用PrepareOperations對(duì)象的findActionMapping(request,response,forceLookup)方法,從request對(duì)象中根據(jù)struts.actionMapping這個(gè)key拿到ActionMapping對(duì)象并返回。如果request中沒(méi)有該對(duì)象或者其為null,則通過(guò)dispatcher.getContainer().getInstance(ActionMapper.class).getMapping(request, dispatcher.getConfigurationManager())來(lái)創(chuàng)建出ActionMapping對(duì)象。
如果當(dāng)前request對(duì)應(yīng)的ActionMapping為null,經(jīng)過(guò)ExecuteOperations對(duì)象execute.executeStaticResourceRequest(request, response)確認(rèn)請(qǐng)求的是靜態(tài)資源對(duì)象(即非Action對(duì)象), 則直接調(diào)用FilterChain對(duì)象的doFilter(request,response) 對(duì)當(dāng)前請(qǐng)求進(jìn)行放行處理;
否則,調(diào)用ExecuteOperations對(duì)象的executeAction方法,在該方法中會(huì)先根據(jù)ActionMapping對(duì)象來(lái)決定是否要調(diào)用struts.xml中注冊(cè)的某個(gè)Action對(duì)象,如果是,則創(chuàng)建對(duì)應(yīng)的ActionProxy(代理對(duì)象),并將請(qǐng)求的處理交給ActionProxy對(duì)象,ActionProxy則創(chuàng)建一個(gè)ActionInvocation的實(shí)例,由ActionInvocation實(shí)例來(lái)實(shí)現(xiàn)對(duì)Action實(shí)例中指定的業(yè)務(wù)方法進(jìn)行調(diào)用。但在調(diào)用Action對(duì)象的前后會(huì)涉及到攔截器?;驍r截器對(duì)象的調(diào)用。
當(dāng)Action被調(diào)用完畢,ActionInvocation會(huì)根據(jù)struts.xml中的配置找到對(duì)應(yīng)的返回結(jié)果result,可以是JSP或html或其他Action鏈等。
注意:在整個(gè)struts框架中,所有的對(duì)象都是由xwork容器負(fù)責(zé)創(chuàng)建和管理的。
8、Struts2的配置相關(guān)的文件及其加載順序(由先到后):
2)struts-default.xml 在struts2-core-?.jar包中,主要包含了框架依賴對(duì)象的配置和結(jié)果類型,以及攔截器等配置;

3)struts-plugin.xml 文件存在于struts-?-plugin-?.jar包中,主要用于配置struts的框架,由框架提供;
4)struts.xml 文件,就是我們?cè)趕truts2項(xiàng)目的source folder目錄中定義的文件。可以用來(lái)配置常量,package和Action,攔截器等;
5)struts.properties 文件,該文件可以由開發(fā)者創(chuàng)建并跟struts.xml文件放在同一個(gè)目錄中,可以用來(lái)覆蓋default.properties中的常量的定義;
6)web.xml文件,該文件是web項(xiàng)目中WEB-INF目錄下的重要配置文件。
注意:由于加載有先后順序,所以后面文件配置中的常量會(huì)覆蓋前面加載的文件中同名的常量。
9. struts2中常見常量介紹:
用于指定默認(rèn)編碼集,用在request.setCharacterEncoding(String)方法中,以及freemarker、velocity等。
其中freemarker是模板引擎,是一種基于模板允許其中key的值變動(dòng),將其生成輸出的文本如html格式的文本的工具)。

其中velocity是一個(gè)基于java的模板引擎, 允許僅使用簡(jiǎn)單的模板語(yǔ)言(template language)來(lái)引用由java代碼定義的對(duì)象。
指定請(qǐng)求資源的后綴名,如.action, 以及沒(méi)有后綴名等。
設(shè)置瀏覽器是否緩存靜態(tài)內(nèi)容,默認(rèn)為true。一般在生產(chǎn)環(huán)境下使用,而在開發(fā)階段為了測(cè)試,最好關(guān)閉。
當(dāng)struts的配置文件(xml格式)修改后,系統(tǒng)自動(dòng)重新加載,而不用重啟tomcat。默認(rèn)為false。
struts.devMode = true
設(shè)置開發(fā)者模式,該模式下修改struts.xml文件后不需要重啟服務(wù)器即可生效。
設(shè)置默認(rèn)的視圖主題樣式,simple指定為簡(jiǎn)化的主題樣式。
struts.enable.DynamicMethodInvocation = false
設(shè)置是否支持動(dòng)態(tài)方法調(diào)用。為true時(shí),就可以在struts.xml配置“*”的通配符,來(lái)調(diào)用action里的方法。
例如:
/pages/success.jsp
/pages/error.jsp
調(diào)用時(shí)就可以通過(guò)url來(lái)傳遞方法名,即動(dòng)態(tài)方法調(diào)用。如:
http://localhost:8080/webproject/pss/login_mymethod
表示系統(tǒng)會(huì)調(diào)用com.abc.action.LoginAction類的對(duì)象中的mymethod方法。該方法返回“success”時(shí),跳轉(zhuǎn)到web根目錄下/pages/success.jsp文件;如果返回“error”時(shí),跳轉(zhuǎn)到web根目錄/pages/error.jsp文件。
10、struts.xml文件的編寫規(guī)則
常量的定義:
如果要在里面定義常量,格式為:
包的定義:
如果要定義包,使用
節(jié)點(diǎn)來(lái)定義。
其中name屬性為包名,不同的包,name值應(yīng)該不同。
extends屬性表示當(dāng)前的包繼承自哪個(gè)包,一般都繼承自struts-default包。繼承了struts-default包,則表示當(dāng)前包擁有了struts-default包所定義的資源,如返回結(jié)果類型,攔截器等。struts-default包是在struts-core-?.jar/struts-default.xml文件中定義。
namespace屬性表示定義了一個(gè)命名空間,一般以”/“開頭,如”/pss“。命令空間和節(jié)點(diǎn)的name屬性組合成了所在包下面的action對(duì)象的訪問(wèn)路徑。如
則action資源的請(qǐng)求路徑為:http://服務(wù)器ip:tomcat端口號(hào)/項(xiàng)目的上下文路徑/包的namespace值/action的name值.action
abstract屬性用來(lái)將包定義為抽象的包,即只能用來(lái)被繼承,而里面沒(méi)有定義任何的節(jié)點(diǎn),也就是沒(méi)有任何的action對(duì)象。
Action實(shí)現(xiàn)類的定義:
class屬性對(duì)應(yīng)Action實(shí)現(xiàn)類的全限定名,默認(rèn)是ActionSupport類;
method屬性指定要調(diào)用Action的業(yè)務(wù)方法;
節(jié)點(diǎn)定義在節(jié)點(diǎn)中或者中,用于配置業(yè)務(wù)方法執(zhí)行結(jié)果對(duì)應(yīng)跳轉(zhuǎn)或重定向到的視圖路徑。
格式為:
name屬性用來(lái)定義邏輯視圖名,對(duì)應(yīng)于action中業(yè)務(wù)方法執(zhí)行后返回的字符串,缺省為"success";
type屬性用來(lái)指定跳轉(zhuǎn)的類型,缺省是dispatcher表示請(qǐng)求轉(zhuǎn)發(fā)到j(luò)sp文件(頁(yè)面),redirect表示重定向到j(luò)sp文件,chain表示從一個(gè)action請(qǐng)求轉(zhuǎn)發(fā)到另一個(gè)action,redirectAction表示從一個(gè)action重定向到另一個(gè)action,stream表示返回流對(duì)象,用于文件下載;
如:/pages/ok.jsp
注意:如果要訪問(wèn)不同命名空間下的action,例如要訪問(wèn)”/pss“命名空間中的name值為hello的action,則在節(jié)點(diǎn)中,添加如下兩個(gè)節(jié)點(diǎn):
/pss
hello
action的擴(kuò)展:比如要執(zhí)行name值為hello的action對(duì)象中的abc()業(yè)務(wù)方法,有三種做法:
1)直接在節(jié)點(diǎn)中配置method屬性的值為abc;
2)http://服務(wù)器ip:端口號(hào)/web項(xiàng)目上下文路徑/package namespace/hello!abc
此種方式需要配置常量:
3)使用通配符
則請(qǐng)求的url為:http://服務(wù)器ip:端口號(hào)/web項(xiàng)目上下文路徑/package namespace/hello_abc
11、如何在Action中獲取request,response,session,cookie等?
首先我們要明白在Servlet中的業(yè)務(wù)方法service方法中,已經(jīng)通過(guò)參數(shù)將HttpServletRequest和HttpServletResponse兩個(gè)對(duì)象傳入進(jìn)來(lái)了,我們可以直接用,通過(guò)request.getSession()就可以拿到Session對(duì)象,通過(guò)request.getCookies()就可以拿到所有的Cookie對(duì)象。
那么我們現(xiàn)在來(lái)看下,在Struts的Action中如何獲取上述四個(gè)對(duì)象呢?有兩種方式:
方式一:(有耦合,不推薦)通過(guò)實(shí)現(xiàn)Struts提供的感知接口來(lái)自動(dòng)獲取,如ServletRequestAware,ServletResponseAware,SessionAware等接口。

之所以能通過(guò)感知接口拿到相關(guān)的Servlet對(duì)象,是因?yàn)樵趕truts-core-?.jar包中的struts-default.xml文件中定義了servletConfig對(duì)應(yīng)的類。

我們來(lái)看看ServletConfigInterceptor類的代碼:

方式二:直接通過(guò)ServletActionContext工具類中的靜態(tài)方法來(lái)獲取相關(guān)對(duì)象。

方式三:(強(qiáng)烈推薦)通過(guò)ActionContext對(duì)象中的方法來(lái)獲取。ActionContext對(duì)象本身代表著當(dāng)前Action對(duì)象的上下文環(huán)境信息,也就是對(duì)應(yīng)著一次請(qǐng)求的相關(guān)信息。

ActionContext.getContext() 獲取到ActionContext的對(duì)象,通過(guò)該對(duì)象調(diào)用getParameters()獲取到所有參數(shù)的Map集合。
ActionContext是線程安全的,里面定義了ThreadLocal actionContext對(duì)象,實(shí)現(xiàn)了將ActionContext對(duì)象與當(dāng)前線程綁定在一起。
12、JSP頁(yè)面與Action組件間相互注入數(shù)據(jù)的幾種方式:
首先我們要明白,凡是請(qǐng)求中的參數(shù),可以在Action中直接使用request.getParameter(key)或者request.getParamterValues(key)方式來(lái)獲取到參數(shù)的值或數(shù)組值。但是這種做法很麻煩,而且需要在Servlet中做類型轉(zhuǎn)換。有沒(méi)有更好的做法呢?當(dāng)然是有,請(qǐng)看下文。
方式一:將Action看做一個(gè)Model對(duì)象,在Action中直接定義private的屬性名,提供對(duì)應(yīng)的setter方法即可。
方式二:(推薦的方式)創(chuàng)建一個(gè)含有屬性的Model類,在Action中通過(guò)對(duì)該Model類提供屬性及getter和setter方法,頁(yè)面會(huì)通過(guò)ognl表達(dá)式對(duì)數(shù)據(jù)進(jìn)行注入。

方式三:創(chuàng)建一個(gè)含有屬性的Model類,讓Action實(shí)現(xiàn)ModelDriven接口,該接口的的泛型類型為該Model類。在Action中創(chuàng)建一個(gè)Model類的對(duì)象作為屬性,在復(fù)寫的getModel()方法中,返回當(dāng)前Action中的Model類的對(duì)象。

顯然方式一如果傳遞的數(shù)據(jù)個(gè)數(shù)比較多時(shí),代碼比較臃腫;方式三需要實(shí)現(xiàn)ModelDriven接口,有耦合性;方式二顯然是最佳的使用方式。但在實(shí)際的開發(fā)中,經(jīng)常是方式二和方式一的組合使用。
13、攔截器Interceptor
所謂的攔截器是指能夠?qū)χ付ˋction對(duì)象的調(diào)用進(jìn)行動(dòng)態(tài)攔截的組件,可以在調(diào)用之前和之后實(shí)施攔截并執(zhí)行某段代碼,也可以完全阻止某個(gè)Action對(duì)象方法的調(diào)用。
攔截器主要的功能是將Action中的一些通用的功能提取出來(lái),定義在攔截器中。當(dāng)某個(gè)Action需要該功能時(shí),只需要給該Action指定對(duì)應(yīng)的攔截器即可。從而提高了代碼的可重用性,也實(shí)現(xiàn)類裝配式和可插拔式的體系結(jié)構(gòu),使得整個(gè)系統(tǒng)結(jié)構(gòu)更加靈活。
攔截器的特點(diǎn):1、簡(jiǎn)化Action的實(shí)現(xiàn),將重復(fù)的單一功能從Action中剝離出來(lái);2、每個(gè)攔截器只實(shí)現(xiàn)某一種特定的功能;3、攔截器的出現(xiàn)實(shí)現(xiàn)了代碼的模塊化編程(可插拔式編程);4、攔截器整合了Actoin中重復(fù)的代碼(功能),提高了代碼的復(fù)用性。
攔截器棧Interceptor Stack,是將多個(gè)攔截器按照一定的順序連接形成的一條鏈。當(dāng)給某個(gè)Action對(duì)象指定了攔截器棧,則在該Action對(duì)象方法被調(diào)用時(shí),會(huì)按照攔截器棧中的先后順序來(lái)指定攔截的攔截方法。
struts內(nèi)置的攔截器都定義在struts-core-?.jar包中的struts-default.xml文件中:

params攔截器,用于把請(qǐng)求參數(shù)設(shè)置到相應(yīng)的Action對(duì)象的屬性中,并自動(dòng)進(jìn)行類型轉(zhuǎn)換;
modelDriven攔截器,用于將getModel()方法返回的模型對(duì)象存入到OgnlValueStack中。一般只需要讓Action實(shí)現(xiàn)ModelDriven接口,即可使得Action配置了該攔截器;
exception攔截器,用在拋異常的時(shí)候,用于捕獲異常;
validation攔截器,用于讀取項(xiàng)目中的*-validation.xml文件,并使得這些文件中聲明的校驗(yàn)生效;
token攔截器,用于核對(duì)當(dāng)前Action請(qǐng)求是否有效,防止重復(fù)提交Action請(qǐng)求;
fileUpload攔截器,用于處理文件上傳;
workflow攔截器,用于校驗(yàn),調(diào)用Action的validate方法,如果有錯(cuò)誤,則重新定位到名為“input”的結(jié)果視圖;
servletConfig攔截器,用于通過(guò)感知接口,獲取感應(yīng)的對(duì)象,如HttpServletRequest, HttpServletResponse,HttpSession等;
14、自定義一個(gè)攔截器
開發(fā)步驟:

2)定義一個(gè)Action,如HelloAction,實(shí)現(xiàn)了ActionSupport接口。
在struts.xml文件中配置如下,注意由于攔截器返回了login,所以也要配置。當(dāng)然我們可以直接把login這個(gè)result配置到中,但是這樣的話,每個(gè)用到該攔截器的action都要配置login。顯然,我們應(yīng)該將login配置為一個(gè)全局的result。
3)接下來(lái)就是對(duì)攔截器的配置,攔截器的配置其實(shí)也是在struts.xml文件中配置的:
首先要通過(guò)節(jié)點(diǎn)來(lái)定義攔截器,即指定對(duì)應(yīng)的類和名字:
在上圖中,我們可以在節(jié)點(diǎn)中定義一個(gè)攔截器棧,在該棧中將默認(rèn)的攔截器棧與我們所定義的攔截器組合成一個(gè)新的攔截器棧。注意順序,先是defaultStack,然后才是我們定義的攔截器。如上圖。
然后通過(guò)節(jié)點(diǎn)來(lái)指定該包下面的action都同一應(yīng)用的攔截器。如:
注意:如果要對(duì)某一個(gè)action不使用我們自定義的攔截器棧,則需要在節(jié)點(diǎn)中聲明使用默認(rèn)的攔截器棧。即:
15、國(guó)際化i18n
所謂的國(guó)際化,指的是讓程序能夠支持在不同的語(yǔ)言環(huán)境下顯示不同語(yǔ)言的內(nèi)容。如在中文環(huán)境下顯示中文內(nèi)容,在英文語(yǔ)言環(huán)境下顯示英文內(nèi)容。
struts2支持國(guó)際化,是由于其內(nèi)置有i18n的攔截器:
那么如何才能在項(xiàng)目中配置國(guó)際化的語(yǔ)言內(nèi)容呢?

首先分別定義不同語(yǔ)言環(huán)境對(duì)應(yīng)的properties文件,如文件名為constant,則中文環(huán)境下的properties文件全名應(yīng)該為constant_zh_CN.properties,英文環(huán)境下的properties文件的全名為constant_en_US.properties。
然后在struts中配置國(guó)際化文件:
最后在jsp文件下要用的話,必須使用taglib命令引入struts標(biāo)簽庫(kù):
在需要從properties文件中拿常量的地方,使用即可拿到key對(duì)應(yīng)的值。
注意:對(duì)于properties文件中key的值,如果要在action中拿到,需要action對(duì)象實(shí)現(xiàn)了ActionSupport接口,通過(guò)getText(key)即可拿到key在不同語(yǔ)言環(huán)境中的value值。
16、OGNL是什么?
Object Graphic Navigation Language對(duì)象圖導(dǎo)航語(yǔ)言,是一種表達(dá)式語(yǔ)言,可以理解為OGNL是EL表達(dá)式語(yǔ)言的一種升級(jí)版,通過(guò)簡(jiǎn)單一致的表達(dá)式語(yǔ)法,可以存取對(duì)象的任意屬性,調(diào)用對(duì)象的方法,遍歷整個(gè)對(duì)象的結(jié)構(gòu)圖,實(shí)現(xiàn)字段類型轉(zhuǎn)化等功能。使用相同的表達(dá)式去存取對(duì)象的屬性,取得對(duì)象中的數(shù)據(jù)。
該表達(dá)式是將對(duì)象的引用值用點(diǎn)串聯(lián)起來(lái),從左到右,每一次表達(dá)式計(jì)算返回的結(jié)果成為當(dāng)前對(duì)象,后面部分接著在當(dāng)前對(duì)象上進(jìn)行計(jì)算,一直到全部表達(dá)式計(jì)算完成,返回最后得到的對(duì)象。OGNL則針對(duì)這條基本原則進(jìn)行不斷的擴(kuò)充,從而使之支持對(duì)象樹、數(shù)組、容器的訪問(wèn),甚至是類似SQL中的投影選擇等操作。
例如,假設(shè)當(dāng)前環(huán)境(對(duì)象)中的根對(duì)象是student,而student對(duì)象中有個(gè)scores數(shù)組,該數(shù)組中第一個(gè)值為總分,則可以通過(guò)ognl表達(dá)式:studet.scores[0]拿到總分的值。
OGNL支持+-*/運(yùn)算符,是struts2默認(rèn)的表達(dá)式語(yǔ)言;支持類的靜態(tài)方法的調(diào)用和值的訪問(wèn);支持賦值操作和表達(dá)式串聯(lián);可以操作集合對(duì)象;可以直接new一個(gè)對(duì)象;
OGNL通常要結(jié)合Struts2的一些標(biāo)志一起使用,如#,$,%;
其中#主要用來(lái)訪問(wèn)ONGL上下文和action上下文,#代表ActionContext.getContext()。
如#parameters.id[0]相當(dāng)于request.getParameterValues("id").get(0);
#request.userName相當(dāng)于request.getAttribute("userName");
#session.userName相當(dāng)于session.getAttribute("userName");
#application.userName相當(dāng)于application.getAttribute("userName");
attr 用于按request > session > application順序訪問(wèn)其屬性(attribute) #attr.userName相當(dāng)于按順序在以上三個(gè)范圍(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來(lái)封裝每一次請(qǐng)求的數(shù)據(jù),也就是說(shuō)每一次請(qǐng)求都會(huì)創(chuàng)建一個(gè)新的ValueStack對(duì)象,在該對(duì)象中封裝了本次請(qǐng)求的相關(guān)數(shù)據(jù)信息。也意味著Struts2中的ValueStack對(duì)象可以使用ognl表達(dá)式來(lái)存取其中的數(shù)據(jù)。那么ValueStack對(duì)象可以通過(guò)request.getAttribute("struts.valueStack")的方式拿到,也可以通過(guò)調(diào)用ActionContext對(duì)象的getValueStack()方法來(lái)拿到。也就是意味著在request對(duì)象中有一個(gè)名為struts.valueStack的key,其對(duì)應(yīng)的值為ValueStack對(duì)象。
我們先看看源碼:

其實(shí)OgnlValueStack對(duì)象的棧結(jié)構(gòu)的實(shí)現(xiàn),是由其里面的root變量來(lái)實(shí)現(xiàn)的。

我們可以在root中拿到當(dāng)前Action的對(duì)象,在context中拿到作用域?qū)ο?request,session,application)的Map格式的對(duì)象及參數(shù)對(duì)象parameters等。
如果要獲取Action對(duì)象中的屬性的值,由于Action對(duì)象本身在root的棧頂位置,所以在jsp中可以通過(guò)來(lái)直接獲取;
注意:
1) 有一種情況會(huì)導(dǎo)致Action不在棧頂位置,例如當(dāng)前Action中new了一個(gè)對(duì)象作為其屬性的值。此時(shí),可以在context的key為params中拿到值。
2) 如果需要從root棧的棧頂拿值,則可以通過(guò)如下方式在jsp中拿到:
如果要獲取的值對(duì)應(yīng)的key在ValueStack的context中,則在jsp中可以通過(guò)的方式獲取。
把數(shù)據(jù)放入ValueStack的root中:valueStack.getRoot().push(Object) ,valueStack.getRoot().add(0,Object),valueStack.set(key, Object),以及在Action中帶有g(shù)etter方法的屬性。
把數(shù)據(jù)放入ValueStack的context中,valueStack.getContext().put(key, value)或者ActionContext.getContext().put(key, value)。
注意:在jsp中如果需要查看valueStack中的所有數(shù)據(jù),則可以添加如下代碼:
18、輸入校驗(yàn)
輸入校驗(yàn),一般用于對(duì)jsp頁(yè)面在提交(發(fā)出請(qǐng)求)時(shí),在被請(qǐng)求的Action中執(zhí)行validate()方法,開發(fā)者只需要在該方法中編寫驗(yàn)證代碼即可。如果驗(yàn)證不通過(guò),只需要調(diào)用super.addFileError("字段名稱","錯(cuò)誤信息")即可在Action中業(yè)務(wù)方法被調(diào)用之前終止當(dāng)前的請(qǐng)求。同時(shí),需要在struts.xml文件中配置名為input的result,用來(lái)指定當(dāng)輸入校驗(yàn)失敗時(shí),需要跳轉(zhuǎn)到的頁(yè)面。
如果某些業(yè)務(wù)方法不需要被校驗(yàn),則可以通過(guò)在該方法上添加注解@SkipValidation即可。

如果只對(duì)Action中的業(yè)務(wù)方法abc()進(jìn)行調(diào)用前的校驗(yàn),則validate()方法的方法名改為validateAbc()即可。
如果需要在某個(gè)方法被校驗(yàn)失敗時(shí)跳轉(zhuǎn)到的不是input視圖,而是其它視圖,比如abc視圖。則可以在被校驗(yàn)的方法上通過(guò)注解來(lái)更改校驗(yàn)失敗的視圖名。如@InputConfig(resultName="abc")。
注意:
validation攔截器已經(jīng)對(duì)input方法作了特殊處理,不會(huì)對(duì)其進(jìn)行校驗(yàn)處理。
validation攔截器只是在調(diào)用input方法時(shí)執(zhí)行了validate或validateXxx方法,當(dāng)校驗(yàn)失敗時(shí),由該validate方法提供調(diào)用addFiledError()方法。在validation攔截器之后有個(gè)workflow攔截器,該攔截器會(huì)檢查FiledError中是否有錯(cuò)誤數(shù)據(jù),如果有,就會(huì)跳轉(zhuǎn)到input結(jié)果碼對(duì)應(yīng)的頁(yè)面。
19、文件上傳
使用struts2提供的文件上傳組件相對(duì)來(lái)說(shuō)比較容易些。
首先,在jsp頁(yè)面中,引入struts2的標(biāo)簽庫(kù)struts-tag,然后在需要上傳文件的地方使用標(biāo)簽來(lái)讓用戶選擇文件:

在提交到的Action中,定義三個(gè)屬性,并提供對(duì)應(yīng)的setter方法,然后在業(yè)務(wù)方法如execute中進(jìn)行文件的copy操作即可。然后在struts.xml文件中注冊(cè)此Action。
注意:文件上傳要求jsp中form的請(qǐng)求時(shí)post,且enctype="multipart/form-data"值。struts2的form標(biāo)簽的method屬性的默認(rèn)值就是post。
我們還可以通過(guò)參數(shù)注入的方式來(lái)設(shè)置FileUploadInterceptor攔截器的允許上傳文件最大值和允許上傳文件類型這兩個(gè)參數(shù)。

具體設(shè)置如下:
1024*1024*5
png,jpg
20、文件下載
