struts 2.0提高效率技巧

本章所要介绍的是一些在使用Struts 2开发web应用时,能够提高生产效率的技巧、技术与特性,这些都是开发人员应当牢记的。这些tip范围很广,包括从列出默认值,到说明应当实现的接口,以及如何创建自定义的声明式验证。
本章中描述的信息只是一个简单的介绍——如果你对哪一个tip感兴趣,就不妨深入研究一下。你可以参考Struts2的文档[url]http://struts.apache.org/2.x/docs/guides.html[/url],或者是通过搜索来看看其他开发人员的想法,以及他们是如何进行应用的。
最后,当你阅读每一个小节的时候,都应该想一下当前的tip应该如何与其他tip配合使用,它与其他tip的区别是什么,你又该怎样把它应用到web开发中去。这样你对它的理解才能更上一个台阶。
Struts2的插件体系结构保证了它的可持续发展。你需要常常访问Struts2的插件注册页面以获得最新的开发进展。这个页面中包括了所有的插件相关的声明,地址为[url]http://cwiki.apache.org/S2PLUGINS/home.html[/url]。它上面已经有了很多第三方的插件,例如JSON,GWT和Spring WebFlow。
重用 Action 的配置
我们曾经讲过把action以package的组织形式来配置管理,并且描述了package如何继承其它的package——但是这样做所带来的好处还没有说清楚。下面我们来看一个完整的例子。这个应用程序用来向游客提供动物园信息。每个洲都会对应有一个portal页面,提供动物,地图等等数据。
完成这项功能的一种方式是让用户可以调用类似“[url]www.myzoo.com/home.action?continent=asia[/url]”这样的URL。这样强化了应用程序的逻辑性,并且可以很容易判断现在所请求的是哪个洲的信息。但是,当我们依赖于要渲染给用户的信息的定义方式时,灵活性就丧失了,因为硬编码的路径信息被添加到了action或者视图中。
灵活一点的方式是提供类似“[url]www.myzoo.com/asia/home.action[/url] ”这样的URL。在使用这种方案时,我们可以提供一个action基类,并配置到默认的package下面。每一个继承的package都可以访问这个action基类。所以如果不进行额外配置的话,“[url]www.myzoo.com/home.action[/url]”实际上调用的就是“[url]www.myzoo.com/asia/home.action[/url]”。
更进一步来说,视图也可以不用任何额外的配置来进行自定义。如果默认的package下面的action是这样的:
<action name="home" class="com.fdar.infoq.HomeAction" >
<result>portal.jsp</result>
</action>
那么Struts2所渲染的JSP就会依赖于URL所提供的,用户调用的命名空间。于是如果URL为“[url]www.myzoo.com/home.action[/url]”,那么“/portal.jsp”就会被渲染,如果URL为“[url]www.myzoo.com/asia/home.action[/url]”,那么被渲染的页面就是“/asia/portal.jsp”。强调一下,这个功能并没有进行多余的配置——因为配置信息提供的是一个JSP相对路径而不是特定的路径名。
在配置中使用模式匹配调配符
有的时候,action的配置文件大小会以令人难以置信的速度增加。为了避免这种现象,我们需要使用模式匹配。它的工作方式是定义一个或多个模式,而URL会与这些模式保持一致。
举个例子会更容易说明这一点。假设你的应用中URL的模式是这样的:“/{module}/{entity}/{action}.action”。这是很常见的模
提高效率技巧 | 41 [url]http://www.infoq.com/cn[/url]
式,对应的URL可能是:“/admin/User/edit.action”,“/admin/User/list.action”和“/admin/User/add.action”。
在类的配置中,会有一个Struts2的action类,名字为“{entity}Action”,而每一个{Action}都是action类里面的一个方法。所有对action中方法的调用要么返回一个被显示的实体的更新页面,要么返回所有被显示的实体的一个列表。
在我们的例子中,“struts.xml”配置就是这样的:
<action name=”*/*/*” method=”{3}”
class=”com.infoq.actions.{1}.{2}Action”>
<result name=”view”>/{1}/update{2}.jsp</result>
<result name=”list”>/{1}/list.jsp</result>
</action>
在action的名字中,每一个星号都是一个通配符。在这个例子中,我们全都用了星号——其实也不必如此。比如说,如果你想要把所有对实体的view动作映射到一起,那么类似于“name=”/*/View*”这样的配置就能完成要求。形如{1},{2}等等的标识符用来获取通配符所对应的值(数字表示了所要获取的值对应的通配符的位置,顺序是从左到右)。
在“struts.properties”文件中(或者使用“struts.xml”的constant标签),你需要确保正确配置了下面的属性:
struts.enable.SlashesInActionNames = true
这个属性设为true以后,action的名字中就可以使用斜杠了。Struts2的默认设置是不允许action的名字中出现斜杠的,需要用package来分割命名空间。
最后,如果你是提供验证和转换的属性文件而不是注解的话,那么就没有什么捷径了。我们会在下面的部分谈到这一点。每一项都要包括action的全名和所需的扩展:例如,前面的例子就要包括“edit-validation.xml”和“edit-conversion.xml”,以及“com.infoq.actions.admin”这个package。
使用替代的URI映射方法 
我们除了在配置中使用通配符以外,还可以使用自定义的映射方案,改变从URI到action和被调用方法的映射关系。用这种方法可以减少配置信息,并且可以在整个应用中保持一致。你可以把URI模式与session信息或其他任何你能想到的信息合并,来决定要调用哪一个action。
这种方法需要实现ActionMapper接口,在该接口中有两个要实现的方法:一个是getMapping(),它把URI转换成已知的配置;另一个是getUriFromActionMapping(),它把一个action配置转换成URI。如下所示:
public interface ActionMapper {
ActionMapping getMapping(
HttpServletRequest request,
ConfigurationManager configManager);
String getUriFromActionMapping(ActionMapping mapping);
}
ActionMapping 类中提供了要调用的action的命名空间,名称,方法,结果和参数。ConfigurationManager 可以用来访问配置信息的提供者(然后就可以进行进一步的自定义)。
Action mapper需要在“struts.xml”中进行配置后才能被使用。Name和type属性的值是不变的——只需要把value属性的值改成自定义的ActionMapper的实现类。
<constant name="struts.mapper.class"
value="com.fdar.infoq.MyActionMapper" />
值得高兴的是我们不需要在所有用到的地方都去实现ActionMapper这个接口,Struts2已经有了几种不同类型的实现。
Restful2ActionMapper类提供了一个ReST型接口的实现,它借鉴了Ruby on Rails里易于使用的URI的设计思路。要注意的是,在Struts2的文档中,这个实现还只是一个试验品。
Restful2ActionMapper首先做的事情是判断要使用的命名空间和action,与你所想的一样——URL的最后一个元素是action名,之前的都是命名空间。但是也有例外,因为属性也会通过URI
传入。把action名,属性名和属性值映射到URI中的模式是这样的:
http://HOST/PACKAGE/ACTION/PARAM_NAME1/PARAM_VALUE1/PARAM_NAME2/PARAM_VALUE2
“PARAM_NAME/PARAM_VALUE”这样的名/值对的数量是没有限制的,如果PARAM_NAME1是“id”的话,那么URI可以简化为:
http://HOST/PACKAGE/ACTION/PARAM_VALUE1/PARAM_NAME2/PARAM_VALUE2
当action被确定下来以后,下一步就是要找到需要调用的方法。这可以使用HTTP方法来做出决定。因为HTML不支持PUT和DELETE方法,所以要有另外的请求属性“__http_method”来提供方法信息。
下面是HTTP方法和URL合并以后的结果:
    ♦ GET: “/user” ——当action被单独使用时,“index”方法会被调用
    ♦ GET: “/user/23” ——当action与参数名/值对一起使用时,“view”方法会被调用,在这里“id”属性的值被设为“23”
    ♦ POST: “/user/23” ——这里HTTP方法是POST而非GET,于是“create”方法将会被调用,“id”或者其他用于标识的值会被包含在URL中,而包含更新信息的名-值对会放在POST数据中
    ♦ PUT: “/user” ——“update”方法会被调用,与POST场景类似,包含信息的名-值对会放在POST数据中而不是URL里面
    ♦ DELTE: “/user/23” ——“remove”方法会被调用,在URL里面提供了唯一的标识符(在这里是“id”,其值为“23”)
    ♦ GET: “/user/23!edit”——“!”被用来描述方法名,所以这里会被调用的是“edit”方法
    ♦ GET: “/user/new” ——“new”后缀表示“editNew”方法会被调用

这里还有一个CompositeActionMapper类。这个实现可以帮助你把多个独立的ActionMapper实现类串连起来。这个串连序列中的每一个类都会被检查,看它是否能够解析URI。如果URI被解析成功,那么就返回结果,如果没有,序列中的下一个类就会被继续检查;如果最终也没有找到匹配的结果,就会返回一个null。
和一般的ActionMapper配置一样,CompositeActionMapper配置中包含有constant节点,它列出了要被串连在一起的ActionMapper的实现类的名字。
<bean name="struts"
type="org.apache.struts2.dispatcher.mapper.ActionMapper"
class="org.apache.struts2.dispatcher.mapper.CompositeActionMapper" />
<constant name="struts.mapper.composite"
value="org.apache.struts2.dispatcher.mapper.DefaultActionMapper,
org.apache.struts2.dispatcher.mapper.RestfulActionMapper" />
了解拦截器的功能
拦截器在Struts2框架中起到了至关重要的作用。通过掌握已有的拦截器,你就可以理解在action处理过程中的每一个步骤了。
另外一个好处会在调试action的时候呈现出来。有时候action并没有那些应有的数据。这常常都是由于拦截器没有被正确应用,或者是拦截器应用的顺序有问题导致的。通过掌握每一个拦截器的作用,问题的定位和解决就容易了很多。
下面是一些可以立刻使用的拦截器,并提供了对应的功能描述。
拦截器名     描述
alias     将同一个参数在请求之间进行命名转换。
chain     使上一个action的属性对当前action可用。常与<result type="chain">结合使用(在上一个action中使用)。

conversionError     把ActionContext的转换错误添加到Action的字段错误中。
createSession     自动创建一个HttpSession,当某一个拦截器需要HttpSession协同工作时(如TokenInterceptor)是很有用的。
debugging     提供多个不同的调试场景,用来查看页面背后的数据结构信息。
execAndWait     在后台执行action,并发送给用户一个等候页面。
exception     把异常映射到对应的结果。
fileUpload     为便捷的文件上传提供支持。
I18n     记忆用户session所使用的locale。
logger     输出action名。
model-driven     如果action实现了ModelDriven,该拦截器会将getModel方法的结果放到值栈上面。
scoped-model-driven    如果action实现了 ScopedModelDriven,该拦截器会从scope中获取并存储模型,然后通过setModel方法将其赋给action。
params     把请求参数赋给action。
static-params     把“struts.xml”定义的参数传给action,它们是<action … />标签下的<param … />子标签。
scope     提供了将action状态存储在session或application scope中的简单机制。
servlet-config     提供了对表示HttpServletRequest 和HttpServletResponse的Map的访问。
timer     输出action的执行时间(包括内嵌的拦截器和视图)。
token     验证action中的有效token,避免提交重复的表单。
token-session     和token拦截器一行,但是在处理无效的token时,将提交的信息保存在session中。
validation     使用在 action-validation.xml中定义的验证器来进行验证。
workflow     调用action中的validate方法。如果有异常的话,就会返回INPUT视图。
store     从session中获取和保存实现了ValidationAware的action的消息/异常/字段异常。

checkbox     添加checkbox的自动处理代码,可以检测没有被选中的checkbox,并给它一个默认值(通常是false),然后作为参数添加。它使用了一个特定名称的隐藏字段来检查未提交的checkbox。未选中的默认值可以被那些不是boolean值的checkbox重写。
profiling     激活对参数的性能监测
roles     只有当用户具有正确的JAAS角色时才能够执行action。
prepare     如果action实现了Preparable,那么就调用它的prepare()方法。

使用提供的拦截器栈
拦截器栈可以将那些应用于各类action的拦截器进行功能分组。拦截器栈构建用于CRUD操作,验证action输入,或是其他任何你所需的功能。但是在创建自己的栈以前,最好先来看一下Struts2提供的拦截器栈。很多标准配置都已经配置完成并可以即刻使用了。另外,每一个插件都可以提供自己的拦截器栈,如果要使用插件所提供的功能的话就要使用插件的拦截器栈。
有两种方法可以使用框架提供的拦截器栈——或者把action放到提供了拦截器栈(通过零配置的注解或者“struts.properties”中的constant)的package下面,或者让定义的新package(其中包括了你创建的action)继承提供了拦截器栈的package:
<package name="mypackage"
extends="struts-default" namespace="/mypackage">

</package>
我们曾经说过,在把应用程序部署为产品之前,你需要检查一下拦截器栈,看看你是否需要其中的某/每一个拦截器。“paramsPrepareParamsStack”和“defaultStack”里面包含有“chain”,“il8n”,“fileUpload”,“profiling”和“debugging”这几个拦截器。它们都是不怎么常用的,我们可以把它们移走,减少不必要的处理工作。 
栈     Description
basicStack     Struts2提供的最常用的栈。提供了异常处理,将HTTP对象和请求/表单参数注入action,和处理转换错误的功能。
validationWorkflowStack     向basic栈中添加验证和工作流的功能。
fileUploadStack     向basic栈中添加对自动文件上传的支持。
modelDrivenStack     向basic栈中添加对模型驱动action的支持。
chainStack     向basic栈中添加对action串连的支持。
i18nStack     向basic栈中添加国际化的功能。
paramsPrepareParamsStack     这是Struts2提供的最复杂的一个栈。它的应用场合是当action的prepare()方法被调用时,用传入的请求参数载入数据(或者执行其他任务),然后重新用请求参数来重写一些载入的数据。它的一个典型应用是更新对象。用id来从数据库中读取对象,然后用从请求中传入的参数重写一些读取的数据。
defaultStack     这是默认的栈。它为绝大多数的应用场景提供了所有的功能。实际上,它包括了核心发布版中几乎所有的可用拦截器。
completeStack     这个栈提供了“defaultStack”的别名,用来向后兼容WebWork的应用。
executeAndWaitStack     向basic栈中添加异步支持action的功能。

利用返回类型 
48 | 深入浅出 STRUTS 2 InfoQ 中文站:时刻关注企业软件开发领域的变化与创新
返回类型使得开发者可以对要渲染给用户的元素进行组合和匹配。实际上,一个action可以有多个结果,而且每个结果都可以有不同的结果类型。
另外一点也需要注意:结果可以是可见的,也可以是不可见的。比如说,我们可以返回HTTP头。
下面是一些已经预配置好的结果类型和一些简要说明。如果你把action放到“struts-default”package下面,或者是继承这个package,这些结果类型就可以使用了:
名称     描述
chain     将一个action的执行与另外一个配置好的action串连起来。用第一个action的getter方法和第二个action的setter方法来完成action之间属性的复制。
dispatcher     渲染JSP。这是默认的结果类型,如果在action配置中没有配置其他的结果类型,它就会被使用。
freemarker     渲染Freemarker模板。
httpheader     返回HTTP头和用户定义的值。
redirect     重定向到任意的URL。
redirect-action     重定向到配置好的action。可以用来提供post完成以后的重定向功能。
stream     将数据流返回给浏览器。可以用来把数据注入PDF,Microsoft Work,图像或其他数据中。
velocity     渲染 Velocity模板。
xslt     使用XSLT来转换已执行完毕的action的属性格式。

利用数据转换
Web开发的一个常见任务就是把基于字符串的表单数据转换成适当的类型,交给模型或者业务服务方法使用。通常这是繁重的人工处理过程。Struts2提供了数据转化功能,将这个过程做了简化。内置的转换机制可以将String转化成下面任意一种格式: 
提高效率技巧 | 49 [url]http://www.infoq.com/cn[/url]
   
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值