1、前言
STRUTS是標(biāo)準(zhǔn)的"模型2"的WEB應(yīng)用框架,其中的ActionServlet代表了"模型2"MVC設(shè)計(jì)模式中的"控制器" 。STRUTS應(yīng)用程序一般使用JSP代碼生成用戶界面,這些代碼不包括任何商業(yè)邏輯,代表了MVC中的”VIEW”部分。需要執(zhí)行商業(yè)邏輯的用戶界面中的表單或超鏈將會(huì)由"控制器" ActionServlet接收和處理。在STRUTS中,只有一個(gè)ActionServlet實(shí)例,這個(gè)實(shí)例將接收和處理應(yīng)用中的相關(guān)用戶交互請求。ActionServlet實(shí)例將選擇和調(diào)用相應(yīng)的ACTION類來處理商業(yè)邏輯。在設(shè)計(jì)模式上,ACTION類被稱為“控制輔助者”,它將修改JavaBeans,這些JavaBeans就是MVC中的” model”部分。本文將分析在STRUTS中進(jìn)行模塊化編程的具體細(xì)節(jié)。
2、樣例描述
我們將作一個(gè)模塊編程的例子,這個(gè)例子包括三個(gè)模塊,缺省模塊、registration模塊和approval模塊。缺省模塊下有資源index.html,我們使用它來連接其它兩個(gè)模塊。registration模塊和approval模塊的編程類似,都包含一個(gè)index.jsp和一個(gè)結(jié)果jsp:result.jsp。下面是目錄結(jié)構(gòu):

目錄結(jié)構(gòu)表明,struts的模塊由配置文件、java類(這里者action和form類)和資源文件構(gòu)成,另外各模塊可以共享web.xml,message (這里是applicatonResources.properties)文件。
我們的例子的界面交互圖可以表示如下:
缺省模塊的index.html包括兩個(gè)鏈接,分別連接兩個(gè)模塊的index.jsp資源,registration模塊的index.jsp提交后,如果驗(yàn)證失敗會(huì)重新返回到該模塊的index.jsp,否則用資源resultok.jsp顯示注冊成功的結(jié)果。模塊approval的index.jsp提交后進(jìn)入到resultok.jsp的界面,顯示批準(zhǔn)與否的結(jié)果。
我們從應(yīng)用程序的文件組成和交互兩方面的模塊情況對我們要實(shí)現(xiàn)的例子進(jìn)行了比較清晰的組織,下面我們講解如何在struts中實(shí)現(xiàn)模塊化編程。
3、STRUTS的模塊化機(jī)制
我們將講解STRUTS的相關(guān)配置,這些配置大部分與模塊化編程有關(guān)系,有些沒關(guān)系但對理解STRUTS程序有利。
3.1 ActionServlet參數(shù)
ActionServlet有好多參數(shù)可供設(shè)置,STRUTS在WEB應(yīng)用部署描述符中定義這些參數(shù):
·Config——逗號相隔的應(yīng)用上下文相對的配置文件的路徑,這些配置文件包含了STRUTS WEB應(yīng)用的缺省模塊的設(shè)置。缺省值為 /WEB-INF/struts-config.xml;
·config/${module} -逗號相隔的應(yīng)用上下文相對的配置文件的路徑,這些配置文件包含了STRUTS WEB應(yīng)用的${module}模塊的設(shè)置。這個(gè)模塊的前綴是/${module},多個(gè)config/${module}參數(shù)定義了多個(gè)STRUTS WEB應(yīng)用模塊;
·convertNull - 如果這個(gè)參數(shù)的值為 true, 數(shù)值型Java 包裝類(比如java.lang.Integer)的初始值將會(huì)是null,而不是0。缺省值[false]
·rulesets-逗號相隔的附加的org.apache.commons.digester.RuleSet列表,Digester在分析配置文件時(shí),除了針對標(biāo)準(zhǔn)的配置元素的RuleSet之外,還會(huì)利用這些對象來分析配置文件,這樣提供了一個(gè)配置擴(kuò)展機(jī)制。
·validatin - 指示我們是否使用驗(yàn)證型的XML分析器來處理配置文件,缺省值為 [true]
3.2 配置文件
我們說STRUTS針對每個(gè)模塊可以有一個(gè)或多個(gè)配置文件,這些配置文件使用XML來書寫,下面是標(biāo)準(zhǔn)的配置文件XML的元素解釋。
3.2.1 元素 action
這個(gè)元素描述了一個(gè)ActionMapping 對象,這個(gè)對象將用來處理用戶針對某個(gè)模塊相對應(yīng)的URI 的請求。
3.2.2元素 action-mappings
這個(gè)元素描述了一個(gè)ActionMapping 對象集,類型是org.apache.struts.action.ActionMapping。與STRUTS的ActionServlet 注冊的URL模式匹配的用戶請求將具體地被這些ActionMapping 對象處理。子元素定義了各個(gè)ActionMapping對象。
3.2.3元素 controller
這個(gè)元素描述了一個(gè)struts模塊運(yùn)行環(huán)境的配置——ControllerConfig bean
3.2.4 元素 data-source
這個(gè)元素描述了一個(gè)DataSource 對象——JDBC 2.0 標(biāo)準(zhǔn)擴(kuò)展。這個(gè)對象將被保存在應(yīng)用上下文中,而且可以象JavaBean 一樣被設(shè)置。
3.2.5 元素 exception
這個(gè)元素向struts系統(tǒng)為一個(gè)exception類型注冊了一個(gè)ExceptionHandler。.
3.2.6 元素 form-bean
這個(gè)元素定義了一個(gè)ActionForm[org.apache.struts.action.ActionForm子類,這個(gè)定義被"action"元素所引用。
3.2.7 元素 form-property
這個(gè)元素描述了一個(gè)配置DynaActionForm 或其子類的JavaBean屬性。當(dāng)這個(gè)元素的父元素"form-bean" 的"type" 是 [org.apache.struts.action.DynaActionForm] 或其子類時(shí)有效。如果使用了一個(gè)定制的DynaActionForm 子類,父元素"form-bean" 的"dynamic"屬性必須設(shè)為 "true"。
3.2.8 元素 forward
這個(gè)元素描述了一個(gè)ActionForward 對象,這個(gè)對象將被Action的doPerform返回。在代碼中一般用一個(gè)邏輯名字來引用ActionForward 對象。一個(gè)"forward" 可以用來描述全局或局部ActionForwards. 全局的 forwards對模塊內(nèi)所有的Action 對象有效,局部forwards 嵌套在 元素內(nèi),只能被相應(yīng)的ActionMapping 中的Action訪問。
3.2.9元素 message-resources
3.2.10元素 plug-in
3.2.11 元素 set-property
目錄:
4、模塊定義
5、模塊選擇
6、總結(jié)
4、模塊定義
通過上面對STRUTS的模塊化機(jī)制的講解,我們現(xiàn)在可以開始實(shí)現(xiàn)我們的模塊化例子程序了。
4.1 Actionservlet參數(shù)
我們在struts的web.xml中定義模塊。下面的代碼定義了三個(gè)模塊:缺省模塊,approval和registration模塊,前綴分別是””,/approval和/registration。
<web-app>
<servlet>
<servlet-name>action</servlet-name>
<servlet-class>org.apache.struts.action.ActionServlet</servlet-class>
<init-param>
<param-name>config</param-name>
<param-value>/WEB-INF/struts-config.xml</param-value>
</init-param>
<init-param>
<param-name>config/approval</param-name>
<param-value>/WEB-INF/struts-config-approval.xml</param-value>
</init-param>
<init-param>
<param-name>config/registration</param-name>
<param-value>/WEB-INF/struts-config-registration.xml</param-value>
</init-param>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet> <servlet-mapping>
<servlet-name>action</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
</web-app> |
這樣在初始化actionservlet的過程中,servletcontext的屬性中就會(huì)有這樣的屬性鍵/值關(guān)系:
4.2 approval模塊配置文件
下面是approval模塊的配置文件,定義了form和action,以及相應(yīng)的forward。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts-config PUBLIC "-//Apache Software Foundation//
DTD Struts Configuration 1.1//EN"
"http://jakarta.apache.org/struts/dtds/struts-config_1_1.dtd">
<struts-config>
<form-beans>
<form-bean name="approvalForm" type="com.i505.struts.approval.form.ApprovalForm">
</form-bean>
</form-beans>
<action-mappings>
<action
attribute="approvalForm"
name="approvalForm"
input="/index.jsp"
path="/approval"
scope="request"
type="com.i505.struts.approval.action.ApprovalAction">
<forward name="success" contextRelative="false" path="/resultok.jsp" />
</action>
</action-mappings>
</struts-config> |
4.3 registration模塊配置文件
下面是registration模塊的配置文件,定義了form和action,以及相應(yīng)的message-resources和forward。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts-config PUBLIC "-//Apache Software Foundation//
DTD Struts Configuration 1.1//EN"
"http://jakarta.apache.org/struts/dtds/struts-config_1_1.dtd">
<struts-config>
<form-beans>
<form-bean name="registrationForm" type="com.i505.struts.registration.form.RegistrationForm" />
</form-beans>
<action-mappings>
<action
attribute="registrationForm"
input="/index.jsp"
name="registrationForm"
path="/registration"
type="com.i505.struts.registration.action.RegistrationAction">
<forward name="success" path="/resultok.jsp" />
</action>
</action-mappings>
<message-resources parameter="com.i505.struts.ApplicationResources"/>
</struts-config> |
5、模塊選擇 本節(jié)主要講述struts中如何選擇模塊,實(shí)現(xiàn)模塊的真正運(yùn)作的。
5.1 action的模塊選擇
當(dāng)我們在瀏覽器中使用http://hostaddress/contextpath/module/action.do式樣的的url時(shí),actionservlet會(huì)根據(jù)module選擇模塊對象,下面是actionservlet處理http請求的代碼:
protected void process(HttpServletRequest request,
HttpServletResponse response)
throws IOException, ServletException {
RequestUtils.selectModule(request, getServletContext());
getRequestProcessor(getModuleConfig(request)).process
(request, response);
} |
RequestUtils.selectModule函數(shù)將使用下面的代碼把url中的模塊前綴(下面代碼的prefix將代表上面url式樣中的/module)指定的模塊對象保存在request屬性中,這個(gè)模塊對象就成了處理這個(gè)請求的當(dāng)前模塊對象:
// Expose the resources for this module
ModuleConfig config = (ModuleConfig)
context.getAttribute(Globals.MODULE_KEY + prefix);
if (config != null) {
request.setAttribute(Globals.MODULE_KEY, config);
}
else {
request.removeAttribute(Globals.MODULE_KEY);
} |
5.2 資源的模塊化
資源(比如jsp)的模塊化是指資源可以按照模塊一樣來組織,比如approval模塊的資源可以放在approval目錄下,而registration模塊的資源則放在registration目錄下,缺省模塊的資源放在webroot下。
url訪問這些資源很簡單,url式樣是 http://hostaddress/contextpath/module/xxx.jsp。對于input和forward訪問這些資源,我們只需直接寫相對于模塊路徑下的路徑,注意它們必須以”/”開頭。如果forward是相對servletcontext的,則要加上模塊路徑。
<action-mappings>
<action
attribute="registrationForm"
input="/index.jsp"
name="registrationForm"
path="/registration"
type="com.i505.struts.registration.action.RegistrationAction">
<forward name="success" path="/resultok.jsp" />
</action>
</action-mappings> |
5.3 Formtag中表單action url的生成
對于模塊編程,struts在formtag的action屬性好像有些問題,這些問題出現(xiàn)在struts沒有考慮直接訪問jsp時(shí)的情況。應(yīng)為forward和直接訪問這兩種環(huán)境是不同的,主要是直接訪問這些JSP,request屬性中沒有模塊對象,而forward訪問這些jsp時(shí)request屬性中有模塊對象。我們需要修改代碼,使得在產(chǎn)生action屬性時(shí)不受jsp所在環(huán)境的影響,也就是我們將在formtag的action屬性中指定模塊,而不是request中得到模塊。下面是registration模塊的index.jsp的代碼,它的formtag的action屬性包括了模塊的前綴/registration:
<%@ taglib uri="/WEB-INF/struts-bean.tld" prefix="bean"%>
<%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html"%>
<head>
<title>申請注冊</title>
<%@ page contentType="text/html;charset=GB2312" %>
</head>
<body>
<html:form action="/registration/registration.do" >
姓名:<html:text property="name" /><html:errors property="name"/><br /><br />
年齡:<html:text property="age" /><html:errors property="age"/><br /><br />
<html:submit />
</html:form>
</body>
</html> |
下面我們來修改struts的相關(guān)代碼達(dá)到這個(gè)效果。
5.3.1 Formtag
Formtag的setAction將識別form tag的acton屬性的module前綴,并分離出真正的模塊相對的action路徑,lookup將直接從ServletContext中獲取模塊配置對象。
private String getActionPath(String action) {
String temp = action.trim();
String x;
int pos=0;
if(!temp.startsWith("/")) temp = "/"+ temp;
pos = temp.indexOf("/", 1);
if(pos<=0) return action;
return temp.substring(pos); }
private String getModulePrefix(String action) {
String result;
int pos;
String temp=action.trim();
if(!temp.startsWith("/")) {
temp= "/"+temp;
}
pos = temp.indexOf("/", 1);
if(pos<=1) return "";
else
return temp.substring(0, pos);
}
public void setAction(String action)
{this.modulePrefix = this.getModulePrefix(action);
this.action = this.getActionPath(action);
}
protected void lookup() throws JspException {
//我們直接從ServletContext中獲取模塊配置對象
moduleConfig = (ModuleConfig)
pageContext.getServletContext().getAttribute(Globals.MODULE_KEY + modulePrefix);
…}
rotected String renderFormStartElement() {
HttpServletResponse response =
(HttpServletResponse) this.pageContext.getResponse();
StringBuffer results = new StringBuffer("<form");
results.append(" name=\"");
results.append(beanName);
results.append("\"");
results.append(" method=\"");
results.append(method == null ? "post" : method);
results.append("\" action=\"");
//我們的action已經(jīng)去掉了modulePrefix,所以我們得重新加上
results.append(
response.encodeURL(
RequestUtils.getActionMappingURL(this.modulePrefix+ this.action, this.pageContext)));
…
} |
5.3.2 Requestutils
Requestutils的getActionMappingURL主要用作附加servletcontext 路徑,因?yàn)槲覀儸F(xiàn)在在action參數(shù)附加了modulePrefix路徑,所以沒必要再追加模塊前綴。
public static String getActionMappingURL(String action, PageContext pageContext)
{
HttpServletRequest request = (HttpServletRequest) pageContext.getRequest();
StringBuffer value = new StringBuffer(request.getContextPath());
ModuleConfig config =
(ModuleConfig) pageContext.getRequest().getAttribute(Globals.MODULE_KEY);
//我們jsp中的formtag的action屬性已經(jīng)表示了模塊,所以我們不能再追加模塊名//
if (config != null) {
//
value.append(config.getPrefix());
// }
// Use our servlet mapping, if one is specified
String servletMapping =
(String) pageContext.getAttribute(Globals.SERVLET_KEY,
PageContext.APPLICATION_SCOPE);
if (servletMapping != null) {
String queryString = null;
int question = action.indexOf("?");
if (question >= 0) {
queryString = action.substring(question);
}
String actionMapping = getActionMappingName(action);
if (servletMapping.startsWith("*.")) {
value.append(actionMapping);
value.append(servletMapping.substring(1));
} else if (servletMapping.endsWith("/*")) {
value.append(servletMapping.substring(0, servletMapping.length() - 2));
value.append(actionMapping);
} else if (servletMapping.equals("/")) {
value.append(actionMapping);
}
if (queryString != null) {
value.append(queryString);
}
}
else {
if (!action.startsWith("/")) {
value.append("/");
}
value.append(action);
}
// Return the completed value
return (value.toString());
} |
6、總結(jié) 模塊化編程有利于提高編程效率,但是struts中的模塊化支持有些小問題,本文詳細(xì)分析了struts支持模塊化編程的機(jī)制,并作了些修改,希望對大家有幫助。另外如果我們可以把其改進(jìn)為模塊化的相關(guān)的東西可以打成一個(gè)包進(jìn)行動(dòng)態(tài)部署(比如approval.mar)的話,那將會(huì)更加有用。
posted on 2005-10-24 22:11
Sung 閱讀(245)
評論(0) 編輯 收藏 所屬分類:
Struts