在學(xué)習(xí)struts2之前,首先我們要明白使用struts2的目的是什么烧颖?它能給我們帶來(lái)什么樣的好處弱左?
設(shè)計(jì)目標(biāo)
1.Struts2是一個(gè)基于MVC設(shè)計(jì)模式的Web應(yīng)用框架,它本質(zhì)上相當(dāng)于一個(gè)servlet炕淮,在MVC設(shè)計(jì)模式中拆火,Struts2作為控制器(Controller)來(lái)建立模型與視圖的數(shù)據(jù)交互。</br>
技術(shù)優(yōu)勢(shì)
Struts2有兩方面的技術(shù)優(yōu)勢(shì)涂圆,一是所有的Struts2應(yīng)用程序都是基于client/server HTTP交換協(xié)議们镜,The Java Servlet API揭示了Java Servlet只是Java API的一個(gè)很小子集,這樣我們可以在業(yè)務(wù)邏輯部分使用功能強(qiáng)大的Java語(yǔ)言進(jìn)行程序設(shè)計(jì)润歉。
二是提供了對(duì)MVC的一個(gè)清晰的實(shí)現(xiàn)模狭,這一實(shí)現(xiàn)包含了很多參與對(duì)所以請(qǐng)求進(jìn)行處理的關(guān)鍵組件,如:攔截器踩衩、OGNL表達(dá)式語(yǔ)言嚼鹉、堆棧。
下面驱富,我們?cè)谏钊肫饰鲆幌聅truts的工作原理锚赤。
原理圖:(structs2核心控制器StrutsPrepareAndExecuteFilter)。老版本structs1是FilterDispatcher
工作原理:
在Struts2框架中的處理大概分為以下幾個(gè)步驟** (這邊官方說(shuō)法有點(diǎn)啰嗦了褐鸥,其實(shí)幾句話就說(shuō)明白了)**
1 客戶端初始化一個(gè)指向Servlet容器(例如Tomcat)的請(qǐng)求
2 這個(gè)請(qǐng)求經(jīng)過(guò)一系列的過(guò)濾器(Filter)(這些過(guò)濾器中有一個(gè)叫做ActionContextCleanUp的可選過(guò)濾器线脚,這個(gè)過(guò)濾器對(duì)于Struts2和其他框架的集成很有幫助,例如:SiteMesh Plugin)
3 接著StrutsPrepareAndExecuteFilte被調(diào)用晶疼,StrutsPrepareAndExecuteFilte詢問(wèn)ActionMapper來(lái)決定這個(gè)請(qǐng)是否需要調(diào)用某個(gè)Action
4 如果ActionMapper決定需要調(diào)用某個(gè)Action酒贬,StrutsPrepareAndExecuteFilter把請(qǐng)求的處理交給ActionProxy
5 ActionProxy通過(guò)Configuration Manager詢問(wèn)框架的配置文件,找到需要調(diào)用的Action類
6 ActionProxy創(chuàng)建一個(gè)ActionInvocation的實(shí)例翠霍。
7 ActionInvocation實(shí)例使用命名模式來(lái)調(diào)用锭吨,在調(diào)用Action的過(guò)程前后,涉及到相關(guān)攔截器(Intercepter)的調(diào)用寒匙。
8 一旦Action執(zhí)行完畢零如,ActionInvocation負(fù)責(zé)根據(jù)struts.xml中的配置找到對(duì)應(yīng)的返回結(jié)果躏将。返回結(jié)果通常是(但不總是,也可 能是另外的一個(gè)Action鏈)一個(gè)需要被表示的JSP或者FreeMarker的模版考蕾。在表示的過(guò)程中可以使用Struts2 框架中繼承的標(biāo)簽祸憋。在這個(gè)過(guò)程中需要涉及到ActionMapper
流程圖:
工作流程:
1、客戶端瀏覽器發(fā)出HTTP請(qǐng)求.
2肖卧、根據(jù)web.xml配置蚯窥,該請(qǐng)求被FilterDispatcher接收
3、根據(jù)struts.xml配置塞帐,找到需要調(diào)用的Action類和方法拦赠, 并通過(guò)IoC方式,將值注入給Aciton
4葵姥、Action調(diào)用業(yè)務(wù)邏輯組件處理業(yè)務(wù)邏輯荷鼠,這一步包含表單驗(yàn)證。
5榔幸、Action執(zhí)行完畢允乐,根據(jù)struts.xml中的配置找到對(duì)應(yīng)的返回結(jié)果result,并跳轉(zhuǎn)到相應(yīng)頁(yè)面
6削咆、返回HTTP響應(yīng)到客戶端瀏覽器
廢話不多說(shuō)牍疏,下面我們開(kāi)始進(jìn)入Structs2的學(xué)習(xí)吧!!!!!!!
一、建立第一個(gè)struts2的程序
a:找到struts目錄下對(duì)應(yīng)的apps目錄
b:解壓struts2-blank.war
c:copy對(duì)應(yīng)的lib的jar文件
d:copy對(duì)應(yīng)的struts.xml到src目錄
e:注釋掉struts.xml的多余內(nèi)容
f:建立HelloStruts2.jsp文件
g:在struts.xml中照原配置進(jìn)行對(duì)應(yīng)的配置
h:修改對(duì)應(yīng)的web.xml拨齐,建立Struts2的filter(參考struts自帶的項(xiàng)目)
二麸澜、模塊講解
- Demo1講解
<package name="default" namespace="/" extends="struts-default">
<action name="hello">
<result name="success">/hello.jsp</result>
</action>
(1)當(dāng)你改<action name="hello">的name時(shí),程序不能及時(shí)給反饋奏黑,需要重新啟動(dòng)
服務(wù)炊邦,這里有一個(gè)<constant name="struts.devMode" value="true" />
devMode-->develepment Mode 開(kāi)發(fā)模式改為true
* Demo2講解: namespace="/" 和訪問(wèn)的路徑一一對(duì)應(yīng)
>```
<constant name="struts.devMode" value="true" />
<package name="font" namespace="/font" extends="struts-default">
<action name="hello">
<result name="success">/hello.jsp</result>
</action>
(1)Namespace:決定了action的訪問(wèn)路徑,默認(rèn)為””,可以接收所有路徑的action可以寫為/熟史,或者/XXX,或者/XXX/yyy,對(duì)應(yīng)的action訪問(wèn)路徑為/index.action,/XXX/index.action,/XXX/yyy/index.action.Namespace最好也用模塊來(lái)命名
<package name="font".......><action name="hello">
A:這里的package name=""馁害,在java里可以建很多包,包下面可以建相同的類名蹂匹。這里意思一樣,當(dāng)有兩個(gè)action name都叫hello,這里可以寫不同的 package name ,比如一個(gè)前臺(tái)jspfont,后臺(tái)backfont,下面action都叫hello,這樣就不容易混亂了碘菜。
B:<result name="success"> 默認(rèn)就是success可以不加
- Demo3講解: Action問(wèn)題
public class demoAction {
public String execute(){
return "shaca";
}
}
<action name="hello" class="com.aiyin.struts2.action.demoAction">
<result name="shaca">/index.jsp</result>
當(dāng)action中有class時(shí),這是會(huì)去到對(duì)應(yīng)的類里面限寞,找類里面的execute()方法忍啸,然后根據(jù)對(duì)應(yīng)返回值“sucess”找到對(duì)應(yīng)的jsp,然后再返回回來(lái)履植。计雌。
當(dāng)你沒(méi)有配置class時(shí),會(huì)默認(rèn)走自己默認(rèn)的class--->extends ActionSupport
implements Action
在企業(yè)開(kāi)發(fā)只用extends ActionSupport
* Demo4講解: 路徑問(wèn)題
>當(dāng)沒(méi)有對(duì)應(yīng)的namespace玫霎,會(huì)返回到web.xml中丟給Tomcat去處理凿滤,會(huì)訪問(wèn)index.jsp
struts2中的路徑問(wèn)題是根據(jù)action的路徑而不是jsp路徑來(lái)路徑,所以盡量不要使用相對(duì)路徑妈橄。<a href="path/path.action">路徑問(wèn)題</a>
解決辦法非常簡(jiǎn)單,統(tǒng)一使用絕對(duì)路徑(在jsp中用request.getContextPath()方法拿到webapp路徑)或者basePath
* Demo5講解:Action執(zhí)行的時(shí)候并不一定要執(zhí)行execute()方法
> 可以在配置文件中配置Action的時(shí)候用method=來(lái)指定執(zhí)行哪個(gè)方法翁脆。也可以在url 地址中動(dòng)態(tài)指定(動(dòng)態(tài)調(diào)用DMI) DynamicMethodInvocation
<action name="path" class="com.aiyin.struts2.action.demoAction" method="add">
動(dòng)態(tài)調(diào)用 需要打開(kāi)下面這個(gè):
<constant name="struts.enable.DynamicMethodInvocation" value="true" />
<a href="path/user!add">添加用戶</a>
* Demo6講解:通配符
<package name="actions" namespace="/actions" extends="struts-default">
<action name="Student" class="com.aiyin.struts2.action.StudentAction" method="{1}">
<result>/Student{1}_success.jsp</result>
</action>
<action name="*" class="com.aiyin.struts2.action.{1}Action" method="{2}">
<result>/{1}{2}_success.jsp</result>
</action>
</package>
<a href="actions/Studentadd">添加學(xué)生</a><br />
* Demo7講解:用Action的屬性接收參數(shù)
//<a href="user/user!add?name=a&age=8">添加用戶</a>
在類里面生成對(duì)應(yīng)的name和age的get和set方法眷蚓,會(huì)自動(dòng)獲取到
* Demo8講解:簡(jiǎn)單數(shù)據(jù)驗(yàn)證
點(diǎn)擊進(jìn)入網(wǎng)頁(yè):[自定義Struts2表單驗(yàn)證后的錯(cuò)誤信息顯示格式](http://www.blogjava.net/lishunli/archive/2010/10/17/335384.html)
this.addFieldError("name", "name is error");
A:<s:fielderror cssStyle="color: red"></s:fielderror>
為什么報(bào)的錯(cuò)前面有小點(diǎn):解壓core jar包,template\simple下fielderror.ftl里有ul,所以我們可以自己重新定義它
B:<s:property value="errors.name[0]"></s:property>
<s:debug></s:debug>
C:使用Struts2驗(yàn)證框架實(shí)現(xiàn)輸入校驗(yàn)
出現(xiàn)提示反番,window-->preferences-->catalog.關(guān)聯(lián)xwork里的dtd
* Demo9講解:訪問(wèn)Web元素
>方一手動(dòng)獲取:
取得request,session,application,HttpServletRequest,HttpServletResponse
HttpServletContext
方二:
implements RequestAware沙热,SessionAware,ApplicationAware
private Map<String,Object> request;
private Map<String,Object> session;
private Map<String,Object> application;
// DI dependency injection
// Ioc inverse of control
public String execute(){
ServletActionContext.getRequest().setAttribute("name", name);
ActionContext.getContext().put("pass", pass);
request.put("r1","request2" );
session.put("s1","session2" );
application.put("a1","application2" );
return "success";
}
public void setApplication(Map<String, Object> application) {
this.application=application;
}
public void setSession(Map<String, Object> session) {
this.session=session;
}
public void setRequest(Map<String, Object> request) {
this.request=request;
}
jsp頁(yè)面
>>${name} ${pass}
<%=request.getAttribute("r1") %>
<%=session.getAttribute("s1") %>
<%=application.getAttribute("a1") %><br />
<s:debug></s:debug><br />
ONGL<s:property value="#request.r1"/><br />
<s:property value="#session.s1"/><br />
<s:property value="#application.a1"/>
* 模塊包含
```<include file="login.xml"></include>```
####三:result類型
result的目的就是告訴Struts2框架罢缸,在執(zhí)行完一個(gè)Action后校读,需要系統(tǒng)做什么?
是把一個(gè)視圖資源呈現(xiàn)給用戶還是執(zhí)行另外一個(gè)Action祖能,result配置起到了一個(gè)“路標(biāo)”的作用。
dispatcher:默認(rèn)就是這個(gè),用來(lái)轉(zhuǎn)向頁(yè)面蛾洛,通常處理JSP
redirect:實(shí)際上dispatcher和redirect的區(qū)別就是在于轉(zhuǎn)發(fā)和重定向的區(qū)別养铸。
chain:用來(lái)處理Action鏈,可以forward跳到另外一個(gè)action
redirectAction:重定向到一個(gè)Action
<package name="resultTypes" namespace="/r" extends="struts-default">
<action name="r1">
<result type="dispatcher">/r1.jsp</result>
</action>
<action name="r2">
<result type="redirect">/r2.jsp</result>
</action>
<action name="r3">
<result type="chain">r1</result>
</action>
<action name="r4">
<result type="redirectAction">r2</result>
</action>
</package>
####四:通配符配置
在開(kāi)發(fā)的過(guò)程中,有時(shí)候我們需要對(duì)于每個(gè)action配置一個(gè)error result頁(yè)面轧膘,一般情況下钞螟,
這個(gè)error result頁(yè)面都是同一個(gè)頁(yè)面。如果在每一個(gè)action中單獨(dú)配置error result的話就太麻煩了谎碍,
這時(shí)候我們就可以配置一個(gè)全局的result鳞滨。這個(gè)全局的result在我們的包中,被所有的action共享蟆淀,
但是不會(huì)被別的包共享
*struts.xml*
<package name="user" namespace="/user" extends="struts-default">
<global-results>
<result name="mianpage">/global.jsp</result>
</global-results>
<action name="user" class="com.aiyin.web.action.UserAction" >
<result name="success">/success.jsp</result>
<result name="error">/error.jsp</result>
</action>
</package>
*Index.jsp*
<a href="user/user?type=1">返回success</a>
<a href="user/user?type=2">返回error</a>
<a href="user/user?type=3">返回global result</a>
*其他包如果也想用則可以繼承user包*
<package name="admin" namespace="/admin" extends="user">
<action name="admin" class="com.aiyin.web.action.AdminAction" >
<result>/admin.jsp</result>
</action>
</package>
public String execute() {
return "mianpage";
}