在这篇《Struts2学习之配置单个Action多控制处理逻辑》文章中,讲到指定method属性时,列举了以下的配置代码:
<struts>
<constant name="struts.enable.DynamicMethodInvocation" value="true" />
<package name="lee" extends="struts-default" namespace="/">
<action name="loginAction" class="com.jellythink.practise.LoginAction" method="login">
<result name="input">/login.jsp</result>
<result name="error">/error.jsp</result>
<result name="success">/success.jsp</result>
</action>
<action name="registAction" class="com.jellythink.practise.LoginAction" method="regist">
<result name="regist">/regist.jsp</result>
</action>
</package>
</struts>
可以发现,上面配置的两个Action,有很大一部分是类似的,存在冗余的现象。在Struts2框架中,允许使用通配符的方式进行配置。下面就利用Struts2框架的这一特性对上述这段配置代码进行重构。
在配置<action .../>
元素时,允许在指定name属性时使用模式字符串(即用“*”代表一个或多个任意字符),接下来就可以在class、method属性及<result .../>
子元素中使用{N}的形式来代表前面第N个星号所匹配的子串。基于此,文章一开始的配置代码可以重构为以下这样:
<struts>
<constant name="struts.enable.DynamicMethodInvocation" value="true" />
<package name="lee" extends="struts-default" namespace="/">
<action name="*Action" class="com.jellythink.practise.LoginAction" method="{1}">
<result name="input">/{1}.jsp</result>
<result name="error">/error.jsp</result>
<result name="success">/success.jsp</result>
</action>
</package>
</struts>
上面的<action name="*Action" .../>
元素不是定义了一个普通Action,而是定义了一系列的逻辑Action。只要用户请求的URL是*Action.action的模式,都可以使用该Action来处理。配置该action元素时,还指定method属性,但该method属性使用了一个表达式{1},该表达式就是name属性值中第一个*的值。例如:如果用户请求的URL为loginAction.action,则调用对应的login方法;如果为registAction.action,则调用regist方法。对于<result .../>
子元素中使用的/{1}.jsp
也是同样的道理。
更多时候,我们希望action对应的class属性也可以进行模式匹配,这样的话灵活性更高。比如现在有两个Action类,分别为:com.jellythink.practise.LoginAction
和com.jellythink.practise.RegistAction
,这两个类分别完成登陆与注册行为。当action的name匹配到loginAction时,则对应的class则为com.jellythink.practise.LoginAction
;当匹配到registAction时,则对应的clas则为com.jellythink.practise.RegistAction
。按照这样的需求,上述的配置代码又可以修改为这样:
<struts>
<constant name="struts.enable.DynamicMethodInvocation" value="true" />
<package name="lee" extends="struts-default" namespace="/">
<action name="*_*" class="com.jellythink.practise.{1}Action" method="{2}">
<result name="input">/{2}.jsp</result>
<result name="error">/error.jsp</result>
<result name="success">/success.jsp</result>
</action>
</package>
</struts>
在上述配置代码中,action的name属性为*_*
,这需要我们在前台页面设置action的值时按照指定的规则进行设定,例如:类名_方法名。当用户请求的URL是Login_login.action的模式时,则{1}代表的值为Login,而对应的{2}代表的值为login;同理,当请求为Regist_regist.action的模式时,则{1}代表的值为Regist,而对应的{2}代表的值为regist。
通过这种方式,配置代码的灵活性更高,写法更简单。
通过使用模式匹配的方式,就会引申出另一个问题。比如有下面这段配置代码:
<struts>
<constant name="struts.enable.DynamicMethodInvocation" value="true" />
<package name="lee" extends="struts-default" namespace="/">
<!--Action1-->
<action name="*Action" class="com.jellythink.practise.{1}Action" method="{1}">
<result name="input">/{1}.jsp</result>
<result name="error">/error.jsp</result>
<result name="success">/success.jsp</result>
</action>
<!--Action2-->
<action name="getBookInfoAction" class="com.jellythink.practise.GetBookInfoAction">
<result name="error">/error.jsp</result>
<result name="success">/success.jsp</result>
</action>
<!--Action3-->
<action name="*" class="com.jellythink.practise.DefaultAction">
<result name="success">/success.jsp</result>
</action>
</package>
</struts>
问题是,如果客户端请求的URL是getBookInfoAction.action,那么到底匹配哪个Action呢?对于Struts2框架来说,规则是这样的:
在日后的工作中,使用这样的技巧来重构代码,会带来很多好处,比如配置代码更加精简了,更加容易管理和维护了,更加容易读懂了等等。如果你说你不想用这些东西,那也好,至少你需要知道有这么个东西的存在,好让你去读懂别人写的代码。
学习总是乏味无趣。
果冻想-一个原创技术文章分享网站。
2016年2月21日 于呼和浩特。
未经允许不得转载:果冻想 » Struts2学习之Action的通配符使用