Struts用户指南
副标题#e#
1. 先容
1.1 Model-View-Controller (MVC) 设计模式
FIXME – 需要一个对该模式一般性的先容。(译注:可以参考机器家产出书社的《设计模式》。)
1.2 将MVC观念映射到Struts组件中
Struts 的体系布局实现了Model-View-Controller设计模式的观念,它将这些观念映射到web应用措施的组件和观念中.
这一体系布局中每个主要的组件都将在下面做具体的接头。
1.3 Model: 系统状态和贸易逻辑JavaBeans
基于MVC的系统中的 Model 部门可以细分为两个观念 — 系统的内部状态, 可以或许改变状态的行为。用语术数语来说,我们可以把状态信息看成名词(事物),把行为看成动词(事物状态的改变)。
凡是说来,你的应用措施将系统内部的状态暗示为一组一个或多个的JavaBeans,利用属性(properties)来暗示状态的细节。依赖于你的应用措施的巨大度,这些beans可以是自包括的(以某种方法知道奈何永久地生存它们的状态信息),可能可以是正面的(facades),知道当被请求时奈何从外部数据源(譬喻数据库)中取得信息。Entity EJBs凡是也用来暗示内部状态。
大型应用措施常常将系统大概的贸易逻辑行为暗示为可以被维护状态信息的beans挪用的要领。举个例子,你有一个为每个当前用户生存在session中的购物车bean,内里是暗示当前用户抉择购置物品的属性。这个bean有一个checkOut()要领用来验证用户的信用卡,将定单发给库房以选择货物和出货。此外系统别离地暗示同样的行为,或者利用Session EJBs。
在一些小型应用措施中,同样的行为又大概嵌入到作为Controller一部门的 Action 类中。这在逻辑很是简朴可能并不想要在其它情况中重用这些贸易逻辑时是得当的。Struts框架支持所有这些要领,但发起将贸易逻辑(“做什么”)和 Action 类(“抉择做什么”)分分开。
1.4 View: JSP页面和暗示组件
基于Struts的应用措施中的 View 部门凡是利用JSP技能来构建。JSP页面包括称为“模版文本”的静态HTML(或XML)文本,加上插入的基于对非凡行为标志表明的动态内容。JSP情况包罗了其用途由JSP类型来描写的一套尺度的行为标志,譬喻 <jsp:useBean> 。别的,尚有一个用来界说你本身标志的尺度机制,这些自界说的标志组织在“定制标志库”中。
Struts包罗了一个辽阔的便于建设用户界面,而且充实国际化的定制标志库,与作为系统 Model 部门一部门的ActionForm beans美好地彼此共同。这些标志的利用将在后头做具体接头。
除了JSP页面和其包括的行为及定制标志,贸易工具常常需要可以或许基于它们在被请求时的当前状态将本身处理惩罚成HTML(或XML)。从这些工具处理惩罚过的输出可以很容易地利用 <jsp:include> 尺度行为标志包罗在功效的JSP页面中。
1.5 Controller: ActionServlet和ActionMapping
应用措施的 Controller 部门会合于从客户端吸收请求(典范环境下是一个运行欣赏器的用户),抉择执行什么贸易逻辑成果,然后将发生下一步用户界面的责任委派给一个适当的View组件。在Struts中,controller的根基组件是一个 ActionServlet 类的servlet。这个servlet通过界说一组映射(由Java接口 ActionMapping 描写)来设置。每个映射界说一个与所请求的URI相匹配的路径和一个 Action 类(一个实现 Action 接口的类)完整的类名,这个类认真执行预期的贸易逻辑,然后将节制分配给适当的View组件来建设响应。
Struts也支持利用包括有运行框架所必须的尺度属性之外的附加属性的 ActionMapping 类的本领。这答允你生存特定于你的应用措施的附加信息,同时仍可操作框架其余的特性。别的,Struts答允你界说节制将重定向到的逻辑名,这样一个行为要领可以请求“主菜单”页面(举例),而不需要知道相应的JSP页面的实际名字是什么。这个成果极大地辅佐你疏散节制逻辑(下一步做什么)和显示逻辑(相应的页面的名称是什么)。
#p#副标题#e#
2. 建设Model组件
2.1 概述
你用到的应用措施的需求文档很大概会合于建设用户界面。然而你应该担保每个提交的请求所需要的处理惩罚也要被清楚的界说。凡是说来,Model 组件的开拓者会合于建设支持所有成果需求的JavaBeans类。一个非凡应用要求的beans的准确特性依赖于详细需求变革会很是的大,可是它们凡是可以分成下面接头的几种范例。然而,首先对“范畴”观念做一个简短的回首是有用的,因为它与beans有关。
2.2 JavaBeans和范畴
在一个基于web的应用措施中,JavaBeans可以被生存在(并从中会见)一些差异“属性”的荟萃中。每一个荟萃都有荟萃保留期和所生存的beans可见度的差异的法则。总的说来,界说保留期和可见度的这些法则被叫做这些beans的 范畴 。JSP类型中利用以下术语界说可选的范畴(在圆括号中界说servlet API中的等价物):
page – 在一个单独的JSP页面中可见的Beans,保留期限于当前请求。(service()要领中的局部变量)
request – 在一个单独的JSP页面中可见的Beans,也包罗所有包括于这个页面或从这个页面重定向到的页面或servlet。(Request属性)
session – 参加一个特定的用户session的所有的JSP和servlet都可见的Beans,超过一个或多个请求。(Session属性)
application – 一个web应用措施的所有JSP页面和servlet都可见的Beans。(Servlet context属性)
记着同一个web应用措施的JSP页面和servlets共享同样一组bean荟萃是很重要的。譬喻,一个bean作为一个request属性生存在一个servlet中,就象这样:
MyCart mycart = new MyCart(…);
request.setAttribute("cart", mycart);
将当即被这个servlet重定向到的一个JSP页面利用一个尺度的行为标志看到,就象这样:
<jsp:useBean id="cart" scope="request"
class="com.mycompany.MyApp.MyCart"/>
2.3 ActionForm Beans
#p#分页标题#e#
Struts框架凡是假定你已经为每一个你的应用措施中请求的输入建设了一个 ActionForm bean(即一个实现了 ActionForm 接口的类)。假如你在你的 ActionMapping 设置文件中界说了这样的beans(见“建设Controller组件”),Struts的controller servlet在挪用适当的 Action 要领前将自动为你执行如下的处事:
用适当的要害字查抄用户的session中是否有适当的类的bean的一个实例。
假如没有这样的session范畴的bean,自动成立一个新的bean并添加到用户的session中。
对每个名字对应于bean中的一个属性的请求参数,挪用相应的set要领。这个操纵雷同于当你以通配符“*”选择所有属性利用尺度的JSP行为标志 <jsp:setProperty> 。
更新的ActionForm bean在被挪用时将被通报给Acton类的perform()要领,以使这些值可以或许当即生效。
当你在写你的ActionForm beans时,记着以下的原则:
ActionForm 接口自己不需要非凡的实现要领。它是用来标识这些特定的beans在整个别系布局中的浸染。典范环境下,一个ActionForm bean只包罗属性的get要领和set要领,没有贸易逻辑。
凡是在一个ActionForm bean中只有很少的输入验证逻辑。这样的beans存在的主要来由是生存用户为相关的表单所输入的大部门近期值 — 甚至在错误被检测到时 — 这样同样的页面可以被重建,陪伴有一组堕落信息,这样用户仅仅需要更正错误的字段。用户输入的验证应该在 Action 类中执行(假如是很简朴的话),可能在适当的贸易逻辑beans中执行。
为每个表单中呈现的字段界说一个属性(用相关的getXxx()和setXxx()要领)。字段名和属性名必需凭据JavaBeans的约定相匹配。譬喻,一个名为 username 的输入字段将引起 setUsername() 要领被挪用。
你应该留意一个“表单”在这里接头时的意义并不必需对应于用户界面中的一个单独的JSP页面。在许多应用措施中一个“表单”(从用户的概念)延伸至多个页面也是很泛泛的。想想看,譬喻,凡是在安装新的应用措施时利用的导航安装措施的用户界面。Struts勉励你界说一个包括所有字段属性的单独的ActionForm bean。不管字段实际上是显示在哪个页面上。同样的,同一表单的差异的页面应该提交到沟通的Action类。假如你遵照这个发起,在大大都环境下,页面设计者可以从头组织差异页面中的字段而不需要改变处理惩罚逻辑。
2.4 系统状态Beans
系统的实际状态凡是暗示为一组一个或多个的JavaBeans类,其属性界说当前状态。譬喻,一个购物车系统包罗一个暗示购物车的bean,这个bean为每个单独的购物者维护,这个bean中包罗(在其它事物之中)一组购物者当前选择购置的项目。别离地,系统也包罗生存用户信息(包罗他们的信用卡和送货地点)、可得到项目标目次和它们当前库存程度的差异的beans。
对付小局限的系统,可能对付不需要长时间生存的状态信息,一组系统状态beans可以包括所有系统曾经经验的特定细节的信息。可能常常是,系统状态beans暗示永久生存在一些外部数据库中的信息(譬喻CustomerBean工具对应于表 CUSTOMERS 中的特定的一行),在需要时从处事器的内存中建设或排除。在大局限应用措施中,Entity EJBs也用于这种用途。
2.5 贸易逻辑Beans
#p#分页标题#e#
你应该把你的应用措施中的成果逻辑封装成对为此目标设计的JavaBeans的要领挪用。这些要领可以是用于系统状态beans的沟通的类的一部门,可能可以是在专门执行贸易逻辑的独立的类中。在后一种环境下,你凡是需要将系统状态beans通报给这些要领作为参数处理惩罚。
为了代码最大的可重用性,贸易逻辑beans应该被设计和实现为它们不知道本身被执行于web应用情况中。假如你发此刻你的bean中你必需import一个 javax.servlet.* 类,你就把这个贸易逻辑绑缚在了web应用情况中。思量从头组织事物使你的 Action 类(Controller任务的一部门,在下面描写)翻译所有从HTTP请求中请求被处理惩罚为对你的贸易逻辑beans属性set要领挪用的信息,然后可以发出一个对 execute() 的挪用。这样的一个贸易逻辑类可以被重用在除它们最初被结构的web应用措施以外的情况中。
依赖于你的应用措施的巨大度和范畴,贸易逻辑beans可以是与作为参数通报的系统状态beans交互浸染的普通的JavaBeans,可能利用JDBC挪用会见数据库的普通的JavaBeans。而对付较大的应用措施,这些beans常常是有状态或无状态的EJBs。
2.6 题外话: 会见干系数据库
许多web应用措施操作一个干系数据库(通过一个JDBC driver会见)来生存应用措施相关的永久数据。 其它应用措施则利用Entity EJBs来实现这个目标,他们委派EJBs本身来抉择奈何维护永久状态。假如你是利用EJBs来实现这个目标,遵照EJB类型中描写的客户端设计模式。
对付基于直接数据库会见的web应用措施,一个普通的设计问题是当需要会见低层数据库时奈何发生一个适当的JDBC毗连工具。办理这个问题有几种要领 — 以下原则描写了推荐的一种要领:
建设或获得一个答允一组数据库毗连被多个用户共享的ConnectionPool类。Struts(当前)没有包罗这样的一个类,可是有许多这样的类可以获得。
当应用措施初始化时,在应用措施展开(deployment)描写符中界说一个有一个“启动时加载”值的servlet。我们将把这个servlet叫做 启动 servlet。在大大都环境下,这个servlet不需要处理惩罚任何的请求,所以没有一个 <servlet-mapping> 会指向它。
在启动servlet的 init() 要领中,设置并初始化一个ConnectionPool类的实例,将其生存为一个servlet context属性(从JSP的概念看等同于一个application范畴的bean)。凡是基于通报给启动servlet初始化参数来设置联接缓冲池是很利便的。
在启动servlet的 destroy() 要领中,包括了释放联接缓冲池所打开的联接的逻辑。这个要领将在servlet容器竣事这个应用措施的时候被挪用。
当 Action 类需要挪用一个需要数据库联接的贸易逻辑bean中的要领(譬喻“insert a new customer”)时,将执行下面的步调:
为这个web应用措施从servelt context属性中获得一个联接缓冲池工具。
挪用联接缓冲池工具的 open() 要领来获得一个在 Action 类挪用中利用的联接。
挪用贸易逻辑bean中符合的要领,将数据库联接工具作为一个参数通报给它。
挪用分派的联接中的 close() 要领,这将引起这个联接为了今后其它请求的重用被返回到缓冲池中。
一个凡是的编程错误是健忘了把数据库联接返回给缓冲池,这将最终导致用完所有的联接。必然要确信 Action 类的逻辑老是返回联接,甚至在贸易逻辑bean抛出一个违例时。
遵照上面推荐的设计模式意味着你可以或许编写你的贸易逻辑类而不需要担忧它们奈何获得一个JDBC联接来利用– 简朴地在任何需要会见数据库的要领中包括一个Connection参数。当你的贸易逻辑类在一个web应用措施中被操作时,分派和释放适当的联接是 Action 类的责任。当你利用沟通的贸易逻辑类时,譬喻,在一个批处理惩罚事情中,提供一个适当的联接是谁人应用措施的责任(这不需要从缓冲池中得到,因为大大都批处理惩罚事情运行于一个单线程情况中)。
3. 建设View组件
3.1 概述
这一章会合于建设应用措施中的 View 组件的任务,主要利用JSP技能成立。出格的,Struts除了提供了与输入表单的交互外还提供了成立国际化应用措施的支持。几个其它的与View相关的主题也被简朴地接头。
3.2 国际化动静
几年之前,应用措施开拓者可以或许思量到仅仅支持他们本国的只利用一种语言(可能有时候是两种)和凡是只有一种数量表示方法(譬喻日期、数字、钱币值)的住民。然而,基于web技能的应用措施的爆炸性增长,以及将这些应用措施展开在Internet或其它被遍及会见的网络之上,已经在许多环境下使得国度的界线淡化到不行见。这种环境转酿成为一种对付应用措施支持国际化(常常被称做“i18n”,因为18是字母“i”和字母“n”之间的字母个数)和当地化的需求。
Struts成立于Java平台之上为成立国际化和当地化的应用措施提供辅佐。需要熟悉的要害观念是:
#p#分页标题#e#
Locale – 基本的支持国际化的Java类是 java.util.Locale 。每个 Locale 代表一个出格的国度和语言选择(加上一个可选的语言变量),以及一套名目假定,譬喻数字和日期等等。
ResourceBundle – java.util.ResourceBundle 类提供支持多种语言动静的根基东西。查察文档中关于 ResourceBundle 类以及你的JDK版本的文档包中关于国际化的更多内容。
PropertyResourceBundle – 一个 ResourceBundle 类的尺度实现答允你利用与初始化properties文件同样的“name=value”语法来界说资源。这对付利用为用于一个web应用措施的动静筹备资源包长短常利便的,因为这些动静凡是都是面向文本的。
MessageFormat – java.text.MessageFormat 类答允你利用运行时指定的参数替换一个动静字符串中的一部门(在这种环境下,是一个从一个资源包获得的动静)。这在你建设一个句子的场所中是有用的,可是词会以差异的语言凭据差异的顺序呈现。动静中的占位符字符串{0}用第一个运行时参数替换,{1}用第二个运行时参数替换,以此类推。
MessageResources – Struts的类 org.apache.struts.util.MessageResources 使你可以或许将一套资源包视做一个数据库,而且答允你为一个特定的Locale(凡是是与当前用户相对应)请求一个特定的动静,而不是为处事器运行在个中的缺省的Locale请求动静。
对付一个国际化的应用措施,遵照JDK文档包中国际化文档所描写的步调来建设一个包括每种语言的动静的属性文件。下面举一个例子说明。
假设你的源代码成立在包 com.mycompany.mypackage 中,因此它生存于一个叫做(相对付你的源目次)com/mycompany/mypackage 的目次中。为建设一个叫做 com.mycompany.mypackage.MyResources 的资源包,你应该在目次 com/mycompany/mypackage 中建设下列文件:
MyResources.properties – 包括你的处事器的缺省语言的动静。假如你的缺省语言是英语,你大概有一个这样的条目:
prompt.hello=Hello
MyResources_xx.properties – 包括ISO语言编程为“xx”(查察ResourceBundle的Java文档页面获得一个当前列表的联接)的同样的动静。对付上面的动静的法语版,你可以有这个条目:
prompt.hello=Bonjour
你可以有你需要的任意多的语言的资源包文件。
当你在web应用措施展开描写符中设置controller servlet时,你需要在一个初始化参数中界说的一件事是应用措施的资源包的基本名。在上述的环境中,这应该是 com.mycompany.mypackage.MyResources 。
3.3 表单和FormBean的交互
大部门web开拓者曾经利用HTML的尺度机能来成立表单,譬喻利用 <input> 标志。用户但愿交互措施具有必然的行为,这些等候中的一个与错误处理惩罚有关 — 假如用户呈现一个错误,应用措施应该答允他们仅仅修改需要修改的部门 — 而不需要从头敲入当前页面或表单中的任何其它信息。
利用尺度的HTML和JSP编程来完全实现这个期望是单调而沉重的。举例来说,一个用户名字段的输入元素看起来可以象是这样(在JSP中)
<input type="text" name="username"
value="<%= loginBean.getUsername() %>">
这很难敲对,会把没有编程观念的HTML开拓者搞糊涂,而且会在HTML编辑器中造成问题。取而代之的是,Struts提供了一种全面的基于JSP 1.1的定制标志库成果的机制来成立表单。上面的环境利用Struts处理惩罚后将象是这样:
<struts:text name="username"/>
没有须要再显式地涉及到从中得到初始值的JavaBean。这将由框架自动处理惩罚。
3.3.1 利用Struts成立表单
一个完整的注册表单将演示Struts相对付直接利用HTML和尺度的JSP成果奈何极大地减轻了处理惩罚表单的疾苦。思量以下称为logon.jsp的页面(来自Struts的例子措施):
<%@ page language="java" %>
<%@ taglib uri="/WEB-INF/struts.tld" prefix="struts" %>
<html>
<head>
<title><struts:message key="logon.title"/></title>
<body bgcolor="white">
<struts:errors/>
<struts:form action="logon.do" name="logonForm"
type="org.apache.struts.example.LogonForm"/>
<table border="0" width="100%">
<tr>
<th align="right">
<struts:message key="prompt.username"/>
</th>
<td align="left">
<struts:text name="username" size="16"/>
</td>
</tr>
<tr>
<th align="right">
<struts:message key="prompt.password"/>
</th>
<td align="left">
<struts:password name="password" size="16"/>
</td>
</tr>
<tr>
<td align="right">
<struts:submit>
<struts:message key="button.submit"/>
</struts:submit>
</td>
<td align="right">
<struts:reset>
<struts:message key="button.reset"/>
</struts:reset>
</td>
</tr>
</table>
</struts:form>
</body> </html>
下面的条目基于这个例子演示在Struts中处理惩罚表单的要害的特性:
#p#分页标题#e#
taglib指令汇报JSP页面编译器从那边找到Struts标志库的 标志库描写符 。在这种环境下,我们利用struts作为前缀来标识来自这个库中的标志,可是可以利用任何你想用的前缀。
这个页面利用了几个 message 标志来从一个包括有这个应用措施所有资源的 MessageResources 工具中查找国际化的动静字符串。为了让这个页面可以或许事情,以下的动静要害字必需在这些资源中被界说:
logon.title – 注册页面的标题
prompt.username – 一个 “Username:” 提示字符串
prompt.password – 一个 “Password:” 提示字符串
button.submit – “Submit”按钮的标签
button.reset – “Reset”按钮的标签
当用户注册时,应用措施可以在用户的session中生存一个 Locale 工具。这个 Locale 将用来选择适当语言的动静。这使得给用户一个切换语言的可选项实现起来变的容易了 — 仅仅改变生存的 Locale 工具,所有的动静就会自动切换。
errors 标志显示由一个贸易逻辑组件生存的任何堕落动静,可能假如没有堕落动静生存就什么都没有。这个标志将在下面做深入的描写。
form 标志基于指定的属性对一个HTML <form> 元素举办处理惩罚。它也将所有在这个表单中的字段与一个生存在要害字 logonForm 下的session范畴的FormBean相关联。这个bean用来为所有的具有与bean中的属性名匹配的名字的输入字段提供初始值。假如适当的bean没有找到,一个新的bean将会被自动成立,利用指定的Java类名。
text 标志对一个范例为“text”的HTML <input> 元素举办处理惩罚。在这种环境下,占据欣赏器屏幕的字符位置的数字也被指定。当页面被执行时,是相对应的bean的 username 属性的当前值(也就是 getUsername() 的返回值)。
password 标志利用要领雷同。差异之处是当用户敲入他们的口令时欣赏器将回应星号字符,而不是输入值。
submit 和 reset 标志在表单低部生成相应的按钮。每个按钮的文本标签利用 message 标志成立,同时带有提示,这样这些值就是国际化的。
3.3.2 输入字段范例支持
Struts为所有以下范例的输入字段界说了标志,带有与其相应的参考信息的超联接。
checkboxes
hidden 字段
password 输入字段
radio 按钮
reset 按钮
select 列表和嵌入的
options
submit 按钮
text 输入字段
textareas
在所有环境下,一个字段标志都必需嵌套在一个 form 标志中,这样字段才知道利用哪个bean来初始化显示的值。
3.3.3 其它有用的暗示标志
在Struts的标志库中有几个其它的标志对付成立用户界面是有辅佐的:
enumerate 为一个指定荟萃的每个元素反复一次标志体(可以是一个Enumeration,一个Hashtable,一个Vector或一个工具数组)。
getProperty 从指定的bean中获得指定的属性,而且在本页面的其余部门作为一个page范畴的bean存在。这是会见一个被 enumerate 利用的荟萃的利便的要领。
ifAttributeExists 只有在一个指定的属性存在于一个指定的范畴中时才对标志体求值。
ifAttributeMissing 只有在一个指定的属性不存在于一个指定的范畴中时才对标志体求值。
ifParameterEquals 只有在一个指定的请求参数具有一个指定的值时才对标志体求值。
ifParameterNotEquals 只有在一个指定的请求参数不具有一个指定的值可能不存在时才对标志体求值。
ifParameterNotNull 只有在一个指定的请求参数包括在这个请求中而且长度大于0时才对标志体求值。
ifParameterNull 只有在一个指定的请求参数不包括在这个请求中可能长度便是0时才对标志体求值。
#p#分页标题#e#
iterate 为一个指定荟萃中的每个元素反复一次标志体(可以是一个Collection,一个Iterator,一个Map,可能一个工具数组)。这个标志在Java2情况中取代了 enumerate 标志。
link 生成一个超联接,当没有cookie支持时自动应用URL编程来维护session状态。
parameter 处理惩罚指定请求参数的值,适内地过滤HTML中有非凡寄义的字符。
property 显示一个表单中定名的bean属性 — 在属性应该是只读时利用这个标志而不是 text 标志。
3.3.4 自动表单验证
除了上面描写的表单和bean的交互外,假如你的bean知道奈何验证它吸收的输入字段,Struts还提供一种附加的机制。为了操作这个特性,使你的bean类实现 ValidatingActionForm 接口,而不是 ActionForm 接口。一个 ValidatingActionForm 增加了一个附加的要领签名:
public String[] validate()
对付一个被controller servlet在bean属性已经组装可是在相应的行为类的 perform() 要领被挪用之前挪用的要领,validate() 要领有以下可选项:
执行适当的验证发明没有错误 — 返回 null 可能一个非0长度字符串数组,而且controller servlet将继承挪用适当的 Action 类的 perform() 要领。
执行适当的验证发明有错误 — 返回一个内容为应该被显示的堕落动静要害字(进入应用措施的MessageResources 包)的字符串数组。controller servlet将作为适合于 <struts:errors> 标志利用的请求属性生存这个数组,而且将节制重定向回输入表单(由这个 ActionMapping 的 inputForm 属性标识)。
正如以前提到的,这个特性完全是可选的。假如你的form bean 仅仅实现了 ActionForm 接口,controller servlet将假设任何请求的验证由action类完成。
3.4 其它的暗示技能
尽量你的应用措施的外表和感受可以完全基于尺度的JSP本领和Struts的定制标志库构建,你也应该思量展开其它改造组件重用、淘汰打点承担可能淘汰堕落的技能。在下面的部门接头几个可选的技能。
3.4.1 特定于应用措施的定制标志
在利用Struts库提供的定制标志之外,很容易成立特定于你建设的应用措施的标志来辅佐成立用户界面。Struts包罗的例子措施用成立以下仅用于实现这个应用措施的标志演示了这个原则:
checkLogon – 查抄一个非凡的会话工具的存在,假如不存在将节制重定向到注册页面。这是用来捕获这样的环境,用户在你的应用措施执行的中间把一个页面做成书签而且试图跳过注册,可能用户的会话超时。
linkSubscription – 为一个具体的定单页面生成一个超联接,它将需要的主要害字值作为一个请求属性通报。这在列出与一个用户相关的定单并提供编辑或删除定单的联接时利用。
linkUser – 为一个用户的一个详细的页面生成一个超联接,它将它将需要的主要害字值作为一个请求属性通报。
这些标志的源代码在 src/example 目次中,在包 org.apache.struts.example 里,还带有一些其它的用在这个应用措施中的Java类。
3.4.2 有包括文件的页面组件
在一个JSP文件(包括定制标志和beans用来会见请求的动态数据)中建设完整的暗示是一种很是普通的设计要领,在Struts包罗的例子措施中被回收。然而许多应用措施要求在单唯一个页面中显示你的应用措施的多个逻辑上独立的部门。
举例来说,一个进口应用措施可以在进口的主页面上有一些可能全部以下的成果: 会见这个进口的一个搜索引擎。
一个或更多的“提供新闻”的显示,含有凭据用户的注册信息定制的感乐趣的标题。
会见与这个进口相关的接头的主题。
假如你的进口提供免费邮件帐号,还要有一个“邮件期待”的提示。
假如你可以或许将事情分别隔,分派差异的开拓者去做差异的片断,那么这个站点差异片断的开拓就会越发简朴。然后,你可以利用JSP技能的 include 本领来将这些片断组合进一个单独的页面。有两种 include 可用,依赖于你但愿输出的组合产生在什么时间:
include 指令 (<%@ include file="xxxxx" %>)在JSP页面被编译时处理惩罚。它用于包罗不需要在请求时改变的HTML代码。它把包罗进来的文本看成静态文本,很象C或C++中的 #include 指令。
include 行为 (<jsp:include page="xxxxx" flush="true" />)在请求时处理惩罚,而且是由处事器透明处理惩罚。这意味着你可以通过把它嵌套在一个雷同ifParameterEquals的标志中有条件地执行include 。
3.4.3 图片处理惩罚组件
一些应用措施要求动态生成图片,就象一个股市陈诉站点的价值图一样。凡是利用两种差异的要领来实现这个需求:
#p#分页标题#e#
处理惩罚一个执行一个servlet请求的URL的超联接。这个servlet将利用一个图象库来生成图片,配置适当的content范例(譬喻 image/gif),而且将图片的字节约发送回欣赏器。欣赏器就会象从一个静态文件中吸收到的一样显示图片。
处理惩罚HTML代码需要下载一个建设请求的图象的Java applet。你可以通过为在处理惩罚的代码中的这个applet配置适当的初始化参数设置这个图象,可能你可以让这个applet与处事器成立本身联接来吸收这些参数。
4. 建设Controller组件
4.1 概述
此刻我们领略了奈何结构你的应用措施的Model和View组件,此刻是会合到 Controller 组件的时候了。Struts包罗一个实现映射一个请求URI到一个行为类的主要成果的servlet。因此你的与Controller有关的主要责任是:
为每一个大概吸收的逻辑请求写一个 Action 类(也就是,一个 Action 接口的实现)
写一个界说类名和与每个大概的映射相关的其它信息的 ActionMapping 类(也就是,一个 ActionMapping 接口的实现)
写行为映射设置文件(用XML)用来设置controller servlet。
为你的应用措施更新web应用措施展开描写符文件(用XML)用来包罗必须的Struts组件。
给你的应用措施添加适当的Struts组件。
4.2 Action类
Action 接口界说一个单一的必需由一个 Action 类实现的要领,就象下面这样:
public ActionForward perform(ActionServlet servlet, ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response)
throws IOException, ServletException;
一个 Action 类的方针是处理惩罚这个请求,然后返回一个标识JSP页面的 ActionForward 工具,节制应该重定向这个JSP页面以生成相应的响应。在 Model 2 设计模式中,一个典范的 Action 类将在它的 perform() 要领中实现下面的逻辑:
验证用户session的当前状态(譬喻,查抄用户已经乐成地注册)。假如 Action 类发明没有注册存在,请求应该重定向到显示用户名和口令用于注册的JSP页面。应该这样做是因为用户大概试图从“中间”(也就是,从一个书签)进入你的应用措施,可能因为session已经超时而且servlet容器建设了一个新的session。
假如验证还没有产生(由于利用一个实现 ValidatingActionForm 接口的form bean),验证这个 form bean 的属性是必需的。假如发明一个问题,看成一个请求属性生存符合的堕落信息要害字,然后将节制重定向回输入表单这样错误可以被更正。
执行要求的处理惩罚来处理惩罚这个请求(譬喻在数据库里生存一行)。这可以用嵌入 Action 类自己的代码来完成,可是凡是应该挪用一个贸易逻辑bean的一个符合的要领来执行。
更新将用来建设下一个用户界面页面的处事器端工具(典范环境下是request范畴或session范畴beans,界说你需要在多长时间内保持这些项目可得到)。
返回一个标识生成响应的JSP页面的适当的 ActionForward 工具,基于新近更新的beans。典范环境下,你将通过在你吸收到的 ActionMapping 工具(假如你利用一个局部于与这个映射上的逻辑名)可能在controller servlet 自己(假如你利用一个全局于应用措施的逻辑名)上挪用 findForward() 获得一个对这样一个工具的引用。
当为 Action 类编程时要记着的设计要点包罗以下这些:
controller servlet仅仅建设一个你的 Action 类的实例,用于所有的请求。这样你需要编写你的 Action 类使其可以或许在一个多线程情况中正确运行,就象你必需安详地编写一个servlet的 service() 要领一样。
辅佐线程安详编程的最重要的原则就是在你的 Action 类中仅仅利用局部变量而不是实例变量。局部变量建设于一个分派给(由你的JVM)每个请求线程的栈中,所以没有须要担忧会共享它们。
尽量不该该,代表你的系统中Model部门的的beans仍有大概抛出违例。你应该在你的 perform() 要领的逻辑中捕获所有这样的违例,而且通过执行以下语句将它们记录在应用措施的日志文件中(包罗相应的栈跟踪信息):
servlet.log("Error message text", exception);
作为一个通用的法则,分派很少的资源并在来自同一个用户(在用户的session中)的请求间保持它们会导致可伸缩性的问题。你应该在将节制重定向到适当的View组件前尽力释放这样的资源(譬喻数据库联接) — 甚至在你挪用的一个bean抛出了一个违例时。
#p#分页标题#e#
别的,你将会想要防备呈现很是大的 Action 类。最简朴的实现途径是将你的成果逻辑嵌入到 Action 类自己,而不是将其写在独立的贸易逻辑beans中。除了使 Action 类难于领略和维护外,这种要领也使得难于重用这些贸易逻辑代码,因为代码被嵌入到一个组件(Action 类)中并被绑缚运行于web应用措施情况中。
包罗在Struts中的例子措施某种水平上延伸了这个设计原则,因为贸易逻辑自己是嵌入到 Action 类中的。这应该被看作是在这个样本应用措施设计中的一个bug,而不是一个Struts体系布局中的固有特性,可能是一个值得仿效的要领。
4.3 ActionMapping实现
为了乐成地运行,Struts的controller servlet需要知道关于每个URI该奈何映射到一个适当的 Action 类的几件事。需要相识的常识封装在一个叫做 ActionMapping 的Java接口中,它有以部属性:
actionClass – 用于这个映射的 Action 类完整的Java类名。第一次一个特定的映射被利用,一个这个类的实例将被建设并为今后重用而生存。
formAttribute – session范畴的bean的名字,当前的这个映射的 ActionForm 被生存在这个bean之下。假如这个属性没有被界说,没有 ActionForm 被利用。
formClass – 用于这个映射的 ActionForm 类完整的Java类名。假如你在利用对form beans的支持,这个类的一个实例将被建设并生存(在当前的用户会话中)
path – 匹配选择这个映射的请求的URI路径。看下面如何匹配的例子。
Struts在一个叫做 ActionMappingBase 的类中包罗了一个 ActionMapping 接口的利便的实现。假如你不需要为你本身的映射界说任何附加的属性,尽量把这个类作为你的 ActionMapping 类好了,就向下面部门描写的那样设置。然而,界说一个 ActionMapping 实现(多数是扩展 ActionMappingBase 类)来包括附加的属性也是大概的。controller servlet知道奈何自动设置这些定制属性,因为它利用Struts的Digester模块来读设置文件。
包罗在Struts的例子措施中,这个特性用来界说两个附加的属性:
failure – 假如Action类检测到它吸收的输入字段的一些问题,节制应该被重定向到的上下文相关的URI。典范环境下是请求发向的JSP页面名,它将引起表单被从头显示(包括Action类配置的堕落动静和大部门最近的来自ActionForm bean的输入值)。
success – 假如Action类乐成执行请求的成果,节制应该被重定向到的上下文相关的URI。典范环境下是筹备这个应用措施的会话流的下一个页面的JSP页面名。
利用这两个特另外属性,例子措施中的 Action 类险些完全独立于页面设计者利用的实际的JSP页面名。 这个页面可以在从头设计时被重定名,然而险些不会影响到 Action 类自己。假如“下一个”JSP页面的名字被硬编码到 Action 类中,所有的这些类也需要被修改。
4.4 Action映射设置文件
controller servlet奈何知道你想要获得的映射?写一个简朴地初始化新的 ActionMapping 实例而且挪用所有适当的set要领的小的Java类是大概的(可是很贫苦)。为了使这个处理惩罚简朴些,Struts包罗一个Digester模块可以或许处理惩罚一个想获得的映射的基于XML的描写,同时建设适当的工具。看 API 文档 以得到关于Digester更多的信息。
开拓者的责任是建设一个叫做 action.xml 的XML文件,而且把它放在你的应用措施的WEB-INF目次中。(留意这个文件并不需要 DTD,因为实际利用的属性对付差异的用户可以是差异的)最外面的XML元素必需是<action-mappings>,在这个元素之中是嵌入的0个或更多的 <action> 元素 — 每一个对应于你但愿界说的一个映射。
来自例子措施的 action.xml 文件包罗“注册”成果的以下映射条目,我们用来说明这个需求:
<action-mappings>
<forward name="logon" path="/logon.jsp"/>
<action path="/logon"
actionClass="org.apache.struts.example.LogonAction"
formAttribute="logonForm"
formClass="org.apache.struts.example.LogonForm"
inputForm="/logon.jsp">
<forward name="success" path="/mainMenu.jsp"/>
</action>
</action-mappings>
就象你所看到的,这个映射匹配路径 /logon (实际上,因为例子措施利用扩展匹配,你在一个JSP页面指定的请求的URI竣事于/logon.do)。当吸收到一个匹配这个路径的请求时,一个 LogonAction 类的实例将被建设(仅仅在第一次)并被利用。controller servlet将在要害字 logonForm 下查找一个session范畴的bean,假如需要就为指定的类建设并生存一个bean。
#p#分页标题#e#
这个 action 元素也界说了一个逻辑名“success”,它在 LogonAction 类中被用来标识当一个用户乐成注册时利用的页面。象这样利用一个逻辑名答允将 action 类断绝于任何由于从头设计位置而大概产生的页面名改变。
这是第二个在任何 action 之外宣告的 forward 元素,这样它就可以被所有的action全局地得到。在这个环境下,它为注册页面界说了一个逻辑名。当你挪用 mapping.findForward() 时在你的 action 代码中,Struts首先查找这个action当地界说的逻辑名。假如没有找到,Struts会自动为你查找全局界说的逻辑名。
4.5 Web应用措施展开描写符
配置应用措施最后的步调是设置应用措施展开描写符(生存在文件WEB-INF/web.xml中)以包罗所有必须的Struts组件。作为一个指南利用例子措施的展开描写符,我们看到下面的条目需要被建设或修改。
4.5.1 设置Action Servlet实例
添加一个条目界说action servlet自己,同时包罗适当的初始化参数。这样一个条目看起来象是这样:
<servlet><servlet-name>action</servlet-name>
<servlet-class>org.apache.struts.action.ActionServlet</servlet-class>
<init-p
aram>
<param-name>application</param-name>
<param-value>org.apache.struts.example.ApplicationResources</param-value>
</init-param>
<init-param>
<param-name>config</param-name>
<param-value>/WEB-INF/action.xml</param-value>
</init-param>
<init-param>
<param-name>debug</param-name>
<param-value>2</param-value>
</init-param>
<init-param>
<param-name>mapping</param-name>
<param-value>org.apache.struts.example.ApplicationMapping</param-value>
</init-param>
<load-on-startup>2</load-on-startup>
</servlet>
controller servlet支持的初始化参数在下面描写,拷贝自 ActionServlet 类的 Javadocs 。方括号描写假如你没有为谁人初始化参数提供一个值时假设的缺省值。
application – 应用措施资源包基类的Java类名。[NONE].
config – 包括设置信息的XML资源的上下文相关的路径。[/WEB-INF/action.xml]
debug – 这个servlet的调试级别,它节制记录几多信息到日志中。[0]
digester – 我们在 initMapping() 中操作的Digester的调试级别,它记录到System.out而不是servlet的日志中。[0]
forward – 利用的ActionForward实现的Java类名。[org.apache.struts.action.ActionForward]
mapping – 利用的ActionMapping实现的Java类名。[org.apache.struts.action.ActionMappingBase]
nocache – 假如配置为 true,增加HTTP头信息到所有响应中使欣赏器对付生成或重定向到的任何响应不做缓冲。[false]
null – 假如配置为 true,配置应用措施资源使得假如未知的动静要害字被利用则返回 null。不然,一个包罗不接待的动静要害字的堕落动静将被返回。[true]
4.5.2 设置Action Servlet映射
有两种凡是的要领来界说将被controller servlet处理惩罚的URL — 前缀匹配和扩展匹配。每种要领的一个适当的映射条目将在下面被描写。
前缀匹配意思是你想让所有以一个非凡值开头(在上下文路径部门之后)的URL通报给这个servlet。这样一个条目看起来可以象是这样:
<servlet-mapping>
<servlet-name>action</servlet-name>
<url-pattern>/execute/*</url-pattern>
</servlet-mapping>
它意味着一个匹配前面描写的 /logon 路径的请求的URL看起来象是这样:
http://www.mycompany.com/myapplication/execute/logon
这里 /myapplicationis 是你的应用措施展开地址的上下文路径。
另一方面,扩展映射基于URL以一个随着界说的一组字符的句点竣事的事实而将URL匹配到action servlet 。譬喻,JSP处理惩罚servlet映射到 *.jsp 模式这样它在每个JSP页面请求时被挪用。为了利用 *.do 扩展(它意味着“做某件事”)映射条目看起来应该象是这样:
<servlet-mapping>
<servlet-name>action</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
而且一个匹配以前描写的 /logon 路径的请求的URI可以看起来象是这样:
http://www.mycompany.com/myapplication/logon.do
4.5.3 设置Struts标志库
下一步,你必需添加一个界说Struts标志库的条目。这个条目看起来应该象是这样:
#p#分页标题#e#
<taglib>
<taglib-uri>/WEB-INF/struts.tld</taglib-uri>
<taglib-location>/WEB-INF/struts.tld</taglib-location>
</taglib>
它汇报JSP系统到那边去找这个库的标志库描写符(在你的应用措施的WEB-INF目次,而不是在外部互联网上的某个处所)。
4.5.4 添加Struts组件到你的应用措施中
为了在你的应用措施运行时利用Struts,你必需将 struts.tld 文件拷贝到你的 WEB-INF 目次,将 struts.jar 文件拷贝到你的 WEB-INF/lib 。