勿以惡小而為之,勿以善小而不為————————–劉備
勸諸君,多行善事積福報,莫作惡
上一章簡單介紹了Struts2的’兩個蝴蝶飛,你好’ (一),如果沒有看過,請觀看上一章
一 Action的三種實現方式
上一章開發的HelloAction和HelloAction2,並沒有繼承任何類或者實現任何接口,但是必須有一個execute() 方法,方法返回值是String類型。
這樣的代碼不容易理解,更並不能使人看得出這個類是干什麼的,甚至不能區分這個控制器類與普通的Java類有什麼區別,通常開發中不這樣做。
我們開發者在開發Struts2框架的時候,希望自己寫的這個Action類能夠具有易理解性,且已經支持某些功能,如參數接收,文件上傳等。
一.一 第一種實現方式(普通Java類,裏面只包含execute()方法)
package com.yjl.web.action;
import org.apache.log4j.Logger;
/**
* @author 兩個蝴蝶飛
* @version 創建時間:2018年8月23日 上午9:41:32
* @description 第一種實現方式,普通java類,
* 有一個execute()方法,也可以多寫幾個方法,用action中的標籤method來控制,可以正常訪問。
*/
public class Hello1Action {
private static Logger logger=Logger.getLogger(Hello1Action.class);
public String execute() {
logger.info("兩個蝴蝶飛,web層你好");
return "success";
}
}
不具有開發時要求的規範性,且不支持某些struts2自身提供的功能。
方法名稱只有一個 execute()
一.二 第二種實現方式(實現Action接口)
package com.yjl.web.action;
import com.opensymphony.xwork2.Action;
/**
* @author 兩個蝴蝶飛
* @version 創建時間:2018年8月23日 上午10:54:03
* @description 第二種實現方式,實現Action接口,重寫裏面的execute()方法
* 有一個execute()方法和五個String類型的常量
*/
public class Hello2Action implements Action{
@Override
public String execute() throws Exception {
return Action.SUCCESS;
//return Action.ERROR;
//return Action.LOGIN;
//return Action.NONE;
//return Action.INPUT;
}
}
注意,Action接口是xwork2包下的接口。
實現了Action接口,使開發者能夠看出來這是一個Action,具有了一定程度上的開發規範,
但是實現了Action接口,所以必須要重寫execute()方法。
一般自己寫Action,構思好之後上來就直接add(), edit(), delete(). select() 這些業務方法,
每次都要重寫execute()方法,不太方便。 而且這種方式不具有struts2中某些功能,如驗證框架和國際化。
Action中接口中有五個常用的結果字符串(好多方法都返回success,error,login,input,none,故將其封裝了一下) .
這些字符串雖然是大寫,然而真實的值是全部小寫.
package com.opensymphony.xwork2;
public abstract interface Action
{
public static final String SUCCESS = "success";
public static final String NONE = "none";
public static final String ERROR = "error";
public static final String INPUT = "input";
public static final String LOGIN = "login";
public abstract String execute()
throws Exception;
}
一.三 繼承ActionSupport類(官方推薦)
package com.yjl.web.action;
import com.opensymphony.xwork2.ActionSupport;
/**
* @author 兩個蝴蝶飛
* @version 創建時間:2018年8月23日 上午11:04:20
* @description 第三種方式,繼承ActionSupport類。
* ActionSupport類實現了Action接口,也有Action中的五個常量.
*/
public class Hello3Action extends ActionSupport{
public String list() {
return "list";
}
}
繼承了ActionSupport類,不需要重新寫execute()方法,直接寫業務方法即可。
ActionSupport類,已經實現了 Action接口。 其具備Action中的五個常量,並且該類還實現了其他接口,
源代碼:
public class ActionSupport implements Action, Validateable, ValidationAware, TextProvider, LocaleProvider, Serializable{
...
public String execute() throws Exception
{
//默認返回的是 success 字符串
return "success";
}
...
}
如驗證框架(Validateable,ValidationAware),國際化(LocaleProvider)。
以後開發中,使用 繼承 ActionSupport 類的形式。
二 配置文件 struts.xml中節點的詳細解釋
在src下有一個struts.xml的配置文件,它配置了開發者自己編寫實現的Action,是struts2框架的核心,不能改變文件名稱。(注意,是struts.xml,並不是struts2.xml,並沒有那個2)。
在struts.xml中,最上面是一個約束, 是一個根節點。
二.一 修改常量節點
在struts-core.jar核心包下,有一個包org.apache.struts2包下,有一個default.properties屬性文件,裏面記錄了很多常用的常量,
其中常見的有:
struts.i18n.encoding=UTF-8
struts.multipart.maxSize=2097152
struts.action.extension=action,,
struts.enable.DynamicMethodInvocation = false
struts.devMode = false
struts.ui.theme=xhtml
struts.ognl.allowStaticMethodAccess=false
建議修改后的值為:
###國際化操作,編碼格式為UTF-8
struts.i18n.encoding=UTF-8
###上傳文件時最大的上傳大小,默認為2M. 根據項目情況具體填寫值,建議後面加兩個00
struts.multipart.maxSize=209715200
###struts的訪問後綴名, struts1框架默認的是 .do
struts.action.extension=action,,
###struts是否可以訪問靜態方法
struts.enable.DynamicMethodInvocation =true
###struts是否是開發者模式
struts.devMode =true
###struts中ui標籤的主題,建議為simple
struts.ui.theme=simple
###ognl中是否可以訪問靜態方法,為true
struts.ognl.allowStaticMethodAccess=true
可以在struts.xml中進行相應的修改,如
<!--修改國際化編碼 -->
<constant name="struts.i18n.encoding" value="UTF-8"></constant>
<!--修改是否為開發者模式 -->
<constant name="struts.devMode" value="true"></constant>
按照name,value值的形式進行填寫。
也可以在src下新建一個struts.properties,然後將這些值放置進去,struts也會自動struts.propeties中的常量值的。
也可以在web.xml中,在 中,以 局部參數的形式傳遞進去。
建議使用第一種方式,在struts.xml中用 ,畢竟這個文件常常打開,出錯了也容易發現。
二.二 分模塊開發
在實際的項目中,有很多的模塊,如果所有的配置都放在一個struts.xml,那麼一旦這個struts.xml被其他人誤操作導致了錯誤,那麼其他人的項目將無法運行的,當配置內容過多時,struts.xml的內容太長,不便於維護,所以最好是分模塊開發,一個模塊用一個配置文件,然後再利用 進行導入, 類似 於jsp中的 靜態包含一樣。
所以建議每一個模塊都寫一個模塊.xml,然後在struts.xml中引入即可。如有三個模塊 User模塊和Class,Course,那麼可以將User的配置放置在user.xml中,Class配置放置在class.xml中,course模塊放置在course.xml,在struts.xml中只需要
<include file="user.xml"></include>
<include file="class.xml"></include>
<include file="course.xml"></include>
靜態包含即可。 注意,file的文件路徑引用是否輸入正確。
正確的位置引用,點擊ctrl+模塊.xml時,可以跳轉到相應的.xml文件中。如果沒有跳轉和反應,那說明位置引用錯誤,需要重新檢查一下。
二.三 包節點
在struts.xml配置文件中,最重要的節點就是package節點。 package,分包。 可以將action進行分包處理。
這樣每一個action或者每一組action用package進行隔開,便於維護,類似於java中package的概念。
二.三.一 <package> 節點的使用
<package name="hello" extends="struts-default" namespace="/">
<!--具體的Action-->
</package>
package中name節點是package的名字,是獨一無二的,不能夠重複。 最好與模塊名相同或者起一個有意義的名稱。
extends節點表示繼承,即package之間可以相互的繼承,來避免重複化功能的編寫。 默認為struts-default。
struts-default中struts已經定義了很多功能,開發者自己寫的包只需要extends 這個包名struts-default,
就擁有了struts已經定義好的功能。 如攔截器功能,文件上傳功能。
用戶也可以自己繼承自己所寫的包 。如父包名為
那麼子包只需要 , 這樣child包不但擁有struts-default的功能,也擁有parent包中的特殊功能,這也是Java的多重繼承的體現。 所以package的name 要符合標識符的規範,具有可讀性。
namespace節點表示命名空間,以/開頭,默認是”/” 。是為了在訪問路徑和訪問請求url方面體現package的分包作用. package中的name是在配置文件中體現分包,namespace是在url中體現分包。 建議開發中,namespace的路徑名與name保持一致。 package中的namespace的值與子節點action中name的值,共同構成了完整的訪問請求路徑。
二.三.二 <package></package> 子節點<action></action>節點的使用
在Hello3Action中定義兩個方法,一個是list()查詢,一個是add()添加的方法。
package com.yjl.web.action;
import org.apache.log4j.Logger;
import com.opensymphony.xwork2.ActionSupport;
/**
* @author 兩個蝴蝶飛
* @version 創建時間:2018年8月23日 上午11:04:20
* @description 測試action標籤中method的方法訪問
*/
public class Hello3Action extends ActionSupport{
private static final long serialVersionUID = 8737138848863458260L;
Logger logger=Logger.getLogger(Hello3Action.class);
public String list() {
logger.info("執行list方法");
return "list";
}
public String add() {
logger.info("執行add方法");
return "add";
}
}
標籤,有三個基本的屬性,
<action name="list" class="com.yjl.web.action.Hello3Action"
method="list">
</action>
其中name為action的名字,表示區別一個package包下的不同的action。 其中這個name的值,不應該隨便取,應該是要訪問的方法名。
在瀏覽器客戶端請求的url為 /項目名/package的namespace名稱/action的name名稱.action;
class為要訪問的那個Action的全限定名稱,是class,用.(點)進行分隔。
其中,class 可以省略, 省略默認為 ActionSupport 類, 全限定名稱為: com.opensymphony.xwork2.ActionSupport
method為要訪問的那個方法名稱,類 extends ActionSupport 后,有很多很多的方法,如list(), add(), delete()等,那麼怎麼知道具體要訪問哪個方法呢? 用method這個屬性. method=”要方法的方法名” ,是方法名。
action還有一個節點是converter,表示所用的是哪一個類型轉換器。(後面會有相應的解釋)
很清楚, action 中的 class指定了訪問的是哪一個action, method 指定了訪問的是哪一個具體的方法, 利用了反射技術實現。
在本實例了有兩個方法,所以要進行寫兩個Action, 一個Action類中會有多個方法,難道要一個個配置多個Action嗎?
Struts2提供了一些簡單的方式
二.三.三 配置Action的三種形式
二.三.三.一 通過配置method的屬性完成
簡單舉例如下:
<action name="list" class="com.yjl.web.action.Hello3Action"
method="list">
</action>
<action name="add" class="com.yjl.web.action.Hello3Action"
method="add">
</action>
缺點: 有幾個方法,就要配置有幾個action,當方法過多時,不易維護。
二.三.三.二 通過配置 通配符完成。
簡單舉例如下:
<action name="Hello3_*" class="com.yjl.web.action.Hello3Action"
method="{1}">
</action>
name的值為: 類簡寫名(去掉Action后)_* method中的值取第一個{1},從1開始,不是從0開始。
這樣訪問Hello3Action中的list方法,訪問路徑就是 Hello3_list
訪問Hello3Action中的add方法,訪問路徑就是Hello3_add
簡化了action的相關配置。
也有的人配置的更狠, 會配置成_, 即:
<action name="*_*" class="com.yjl.web.action.{1}Action"
method="{2}">
</action>
User類中的list就是User_list, User類中的add就是User_add,
Class類中的list就是Class_list,Class類中的add就是Class_add
這樣雖說簡化了開發,但卻不利用 result 節點的維護 ,不建議這樣配置。
好多類的好多方法返回值,都寫在這一個action 下面,會亂。
二.三.三.三 動態方法訪問
不是用 * 通配符,而是用! 號。 即:
想訪問UserAction中list方法() 前端寫url為 userAction!list.action
想訪問UserAction中add方法() 前端寫url為 userAction!add.action
想訪問ClassAction中list方法() 前端寫url為 classAction!list.action
想訪問ClassAction中add方法() 前端寫url為 classAction!add.action
這樣訪問也特別的方便。
這樣的話, action中只需要配置name和class即可。 method已經由外部指定了,不需要寫method的值了。
需要先添加變量 struts.enable.DynamicMethodInvocation, 使其變成 true,開啟。
<constant name="struts.enable.DynamicMethodInvocation" value="true"></constant>
如果是UserAction的話,配置應該是:
<action name="userAction" class="com.yjl.web.action.UserAction" >
</action>
ClassAction的話,配置應該是
<action name="classAction" class="com.yjl.web.action.ClassAction" >
</action>
二.三.四 action子節點result的配置
result表示結果,是對方法的返回值進行相應的分析。有兩個屬性,name和type
<result name="success" type="dispatcher">/index.jsp</result>
其中name的值要與方法的返回值保持一致。
如 list方法返回值是return SUCCESS,那麼這個list方法的返回值對應的result的值就是 ,
如果返回是”hello”, 那麼這個name的返回值就是
如果在action中配置通配符, name=Hello3_*形式,method=”{1}”, 那麼為了簡化result的配置,可以將result配置成 name={1},
相應的.jsp,可以變成 /{1}.jsp。
但這樣必須保證Action中方法的名稱與返回值的名稱相同,並且與跳轉到的jsp的名稱也要相同, 這樣不太好。
result中type五種常見的形式, dispatcher(轉發到jsp),redirect(重定向到jsp), chain(轉發到另外一個方法),redirectAction(重定向到另外一個方法),stream(上傳和下載流)
其中dispathcer和redirect是跳轉到jsp,如果想要傳遞數據,用dispather,
如果不想傳遞數據,用redirect (dispathcer是轉發,redirect是重定向)
chain,redirectAction是跳轉到action的操作,一般用於這同一個類中兩個方法之間的跳轉,
如add()添加成功之後,需要跳轉到list()方法進行显示結果,這時就可以配置成:
<result name="add" type="redirectAction">Hello3_list</result>
地址url也會相應的改變,如果是chain的話,地址欄是不會改變的。 chain是轉發到action, redirectAction是重定向到action.
也可以在不同包之間的action進行的跳轉 。
如 add 方法 想到跳轉到 /class 命名空間下的 Hello2Action 的 list 方法。
<result name="add" type="redirectAction">
<!-- 要跳轉到哪一個命名空間,即哪一個包 -->
<param name="namespace">/class</param>
<!-- 要跳轉到哪一個Action 不加後綴 -->
<param name="actionName">Hello2Action</param>
<!-- 跳轉到哪一個方法 -->
<param name="method">list</param>
<!-- 可能要傳遞的參數. 用ognl表達式,根據情況添加 -->
<param name="id">${id}</param>
</result>
通過 param 標籤來配置帶參還是不帶參。
二.四 全局結果頁面與局部結果頁面。
這個全局是相對於package來說的,是package中的全局,並不是所有的struts.xml中的全局,所以全局結果的節點位置應該放在package節點裏面,與action節點平行。 用 節點。
常用的全局結果頁面有兩種:
error錯誤頁面,頁面出錯了都显示這個頁面,
login 登錄頁面, 如果沒有登錄,輸入任何url都會跳轉到login頁面(認證時用)
noprivilege 沒有權限頁面,如果用戶沒有權限訪問了某一個頁面,會給出相應的提示(授權時用)
<global-results>
<result name="error">/error/error.jsp</result>
<result name="login">/login.jsp</result>
<result name="noprivilege">/noprivilege.jsp</result>
</global-results>
當全局結果頁面與局部結果頁面發生衝突時,以局部結果頁面為準。
全局配置時:
<global-results>
<result name="success">/successGlobal.jsp</result>
</global-results>
在該包下的某個action 的方法result 也返回了 success
<result name='success'>success.jsp</result>
那麼,當邏輯視圖為 success時,最終將返回 success.jsp
二.五 配置跳轉頁面
在開發中,常常有這麼一種情況,
請求login.jsp 時,為 /login, 那麼就跳轉到 login.jsp 頁面,
語法為 register.jsp 時,為 /register, 那麼就跳轉到 register 頁面。
這個時候,配置 為:
<action name="*">
<result>/WEB-INF/content/{1}.jsp</result>
</action>
將頁面放置在 content 文件夾下面,避免用戶直接訪問 jsp頁面。
注意,要將此 action 放置在最後, 當所有上面的action都不匹配時,才匹配這一個action.
三 Struts2的執行流程
當用戶在客戶端發送一個請求后,如常用的標準的http://localhost:8080/Struts_Hello/user/User_add.action時,
會經過前端控制器(StrutsPrepareAndExecuteFilter) 過濾器,執行一連串的過濾器鏈,然後根據user 找到了對應的package的namespape,進入到具體的package包下。 利用通配符的方式進行訪問,User_add會進行匹配相應的action,根據class和method找到是哪一個類的哪一個方法,在實例化類Action之前,會先執行攔截器。通過反射實例化類,運行方法, 方法運行成功之後,有一個返回值,這個返回值會與剛才action下的 中的name進行相應的匹配,匹配到哪一個,就執行哪一個result。 如果是diapatcher或者redirect,就显示到相應的.jsp頁面(帶有數據), 如果是chain或者redirectAction,那麼就去執行那一個方法,之後進行返回具體的視圖。
執行過程圖如下:
謝謝您的觀看!!!
本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理
【其他文章推薦】
※帶您來了解什麼是 USB CONNECTOR ?
※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面
※如何讓商品強力曝光呢? 網頁設計公司幫您建置最吸引人的網站,提高曝光率!
※綠能、環保無空污,成為電動車最新代名詞,目前市場使用率逐漸普及化
※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益
※教你寫出一流的銷售文案?
※別再煩惱如何寫文案,掌握八大原則!