IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    Struts2学习之Action的通配符使用

    果冻想发表于 2016-06-02 14:02:35
    love 0

    这么冗余的代码

    在这篇《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框架来说,规则是这样的:

    • 如果请求URL是getBookInfoAction.action,如果struts.xml文件中有名为getBookInfoAction的Action配置,则一定由该Action来处理用户请求
    • 如果struts.xml文件中没有名为getBookInfoAction的Action配置,则搜寻name属性值能匹配getBookInfoAction的Action,例如name为Action或,*Action并不会比*更优先匹配getBookInfoAction的请求,这取决于这两个Action定义的先后顺序

    总结

    在日后的工作中,使用这样的技巧来重构代码,会带来很多好处,比如配置代码更加精简了,更加容易管理和维护了,更加容易读懂了等等。如果你说你不想用这些东西,那也好,至少你需要知道有这么个东西的存在,好让你去读懂别人写的代码。

    学习总是乏味无趣。
    果冻想-一个原创技术文章分享网站。

    2016年2月21日 于呼和浩特。

    未经允许不得转载:果冻想 » Struts2学习之Action的通配符使用



沪ICP备19023445号-2号
友情链接